コード例 #1
0
            private void LowerDecisionTree(BoundExpression expression, DecisionTree decisionTree)
            {
                if (decisionTree == null)
                {
                    return;
                }

                // If the input expression was a constant or a simple read of a local, then that is the
                // decision tree's expression. Otherwise it is a newly created temp, to which we must
                // assign the switch expression.
                if (decisionTree.Temp != null)
                {
                    // Store the input expression into a temp
                    if (decisionTree.Expression != expression)
                    {
                        var convertedExpression = _factory.Convert(decisionTree.Expression.Type, expression);
                        _loweredDecisionTree.Add(_factory.Assignment(decisionTree.Expression, convertedExpression));
                    }

                    if (_declaredTempSet.Add(decisionTree.Temp))
                    {
                        _declaredTemps.Add(decisionTree.Temp);
                    }
                    else
                    {
                        // we should only attempt to declare each temp once.
                        throw ExceptionUtilities.Unreachable;
                    }
                }

                switch (decisionTree.Kind)
                {
                case DecisionTree.DecisionKind.ByType:
                {
                    LowerDecisionTree((DecisionTree.ByType)decisionTree);
                    return;
                }

                case DecisionTree.DecisionKind.ByValue:
                {
                    LowerDecisionTree((DecisionTree.ByValue)decisionTree);
                    return;
                }

                case DecisionTree.DecisionKind.Guarded:
                {
                    LowerDecisionTree((DecisionTree.Guarded)decisionTree);
                    return;
                }

                default:
                    throw ExceptionUtilities.UnexpectedValue(decisionTree.Kind);
                }
            }
コード例 #2
0
        /// <summary>
        /// <![CDATA[
        /// fixed(int* ptr = &v){ ... }    == becomes ===>
        ///
        /// pinned ref int pinnedTemp = ref v;    // pinning managed ref
        /// int* ptr = (int*)&pinnedTemp;         // unsafe cast to unmanaged ptr
        ///   . . .
        /// ]]>
        /// </summary>
        private BoundStatement InitializeFixedStatementRegularLocal(
            BoundLocalDeclaration localDecl,
            LocalSymbol localSymbol,
            BoundFixedLocalCollectionInitializer fixedInitializer,
            SyntheticBoundNodeFactory factory,
            out LocalSymbol pinnedTemp)
        {
            TypeSymbol      localType       = localSymbol.Type;
            BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression);

            // initializer expr should be either an address(&) of something or a fixed field access.
            // either should lower into addressof
            Debug.Assert(initializerExpr.Kind == BoundKind.AddressOfOperator);

            TypeSymbol initializerType = ((PointerTypeSymbol)initializerExpr.Type).PointedAtType;

            // initializer expressions are bound/lowered right into addressof operators here
            // that is a bit too far
            // we need to pin the underlying field, and only then take the address.
            initializerExpr = ((BoundAddressOfOperator)initializerExpr).Operand;

            // intervening parens may have been skipped by the binder; find the declarator
            VariableDeclaratorSyntax declarator = fixedInitializer.Syntax.FirstAncestorOrSelf <VariableDeclaratorSyntax>();

            Debug.Assert(declarator != null);

            pinnedTemp = factory.SynthesizedLocal(
                initializerType,
                syntax: declarator,
                isPinned: true,
                //NOTE: different from the array and string cases
                //      RefReadOnly to allow referring to readonly variables. (technically we only "read" through the temp anyways)
                refKind: RefKind.RefReadOnly,
                kind: SynthesizedLocalKind.FixedReference);

            // NOTE: we pin the reference, not the pointer.
            Debug.Assert(pinnedTemp.IsPinned);
            Debug.Assert(!localSymbol.IsPinned);

            // pinnedTemp = ref v;
            BoundStatement pinnedTempInit = factory.Assignment(factory.Local(pinnedTemp), initializerExpr, isRef: true);

            // &pinnedTemp
            var addr = new BoundAddressOfOperator(
                factory.Syntax,
                factory.Local(pinnedTemp),
                type: fixedInitializer.ElementPointerType);

            // (int*)&pinnedTemp
            var pointerValue = factory.Convert(
                localType,
                addr,
                fixedInitializer.ElementPointerTypeConversion);

            // ptr = (int*)&pinnedTemp;
            BoundStatement localInit = InstrumentLocalDeclarationIfNecessary(localDecl, localSymbol,
                                                                             factory.Assignment(factory.Local(localSymbol), pointerValue));

            return(factory.Block(pinnedTempInit, localInit));
        }
コード例 #3
0
        private BoundStatement InitializeFixedStatementStringLocal(
            BoundLocalDeclaration localDecl,
            LocalSymbol localSymbol,
            BoundFixedLocalCollectionInitializer fixedInitializer,
            SyntheticBoundNodeFactory factory,
            out LocalSymbol stringTemp,
            out LocalSymbol localToClear)
        {
            TypeSymbol      localType       = localSymbol.Type;
            BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression);
            TypeSymbol      initializerType = initializerExpr.Type;

            // intervening parens may have been skipped by the binder; find the declarator
            VariableDeclaratorSyntax declarator = fixedInitializer.Syntax.FirstAncestorOrSelf <VariableDeclaratorSyntax>();

            Debug.Assert(declarator != null);

            stringTemp = factory.SynthesizedLocal(initializerType, syntax: declarator, isPinned: true, kind: SynthesizedLocalKind.FixedString);

            // NOTE: we pin the string, not the pointer.
            Debug.Assert(stringTemp.IsPinned);
            Debug.Assert(!localSymbol.IsPinned);

            BoundStatement stringTempInit = factory.Assignment(factory.Local(stringTemp), initializerExpr);

            var convertedStringTemp = factory.Convert(
                localType,
                factory.Local(stringTemp),
                fixedInitializer.ElementPointerTypeConversion);

            BoundStatement localInit = InstrumentLocalDeclarationIfNecessary(localDecl, localSymbol,
                                                                             factory.Assignment(factory.Local(localSymbol), convertedStringTemp));

            BoundExpression notNullCheck = MakeNullCheck(factory.Syntax, factory.Local(localSymbol), BinaryOperatorKind.NotEqual);
            BoundExpression helperCall;

            MethodSymbol offsetMethod;

            if (TryGetWellKnownTypeMember(fixedInitializer.Syntax, WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__get_OffsetToStringData, out offsetMethod))
            {
                helperCall = factory.Call(receiver: null, method: offsetMethod);
            }
            else
            {
                helperCall = new BoundBadExpression(fixedInitializer.Syntax, LookupResultKind.NotInvocable, ImmutableArray <Symbol> .Empty, ImmutableArray <BoundNode> .Empty, ErrorTypeSymbol.UnknownResultType);
            }

            BoundExpression addition       = factory.Binary(BinaryOperatorKind.PointerAndIntAddition, localType, factory.Local(localSymbol), helperCall);
            BoundStatement  conditionalAdd = factory.If(notNullCheck, factory.Assignment(factory.Local(localSymbol), addition));

            localToClear = stringTemp;
            return(factory.Block(stringTempInit, localInit, conditionalAdd));
        }
コード例 #4
0
        private BoundExpression Visit(BoundExpression node)
        {
            if (node == null)
            {
                return(null);
            }
            CSharpSyntaxNode old = Bound.Syntax;

            Bound.Syntax = node.Syntax;
            var result = VisitInternal(node);

            Bound.Syntax = old;
            return(Bound.Convert(ExpressionType, result));
        }
コード例 #5
0
        private static BoundStatement ConstructNullCheckHelperCall(ParameterSymbol parameter, ref MethodSymbol?throwIfNullMethod, SyntheticBoundNodeFactory factory)
        {
            if (throwIfNullMethod is null)
            {
                var module           = factory.ModuleBuilderOpt !;
                var diagnosticSyntax = factory.CurrentFunction.GetNonNullSyntaxNode();
                var diagnostics      = factory.Diagnostics.DiagnosticBag;
                Debug.Assert(diagnostics is not null);
                throwIfNullMethod = module.EnsureThrowIfNullFunctionExists(diagnosticSyntax, factory, diagnostics);
            }

            var call = factory.Call(
                receiver: null,
                throwIfNullMethod,
                arg0: factory.Convert(factory.SpecialType(SpecialType.System_Object), factory.Parameter(parameter)),
                arg1: factory.StringLiteral(parameter.Name));

            return(factory.HiddenSequencePoint(factory.ExpressionStatement(call)));
        }
コード例 #6
0
        private BoundStatement InitializeFixedStatementArrayLocal(
            LocalSymbol localSymbol,
            BoundFixedLocalCollectionInitializer fixedInitializer,
            SyntheticBoundNodeFactory factory,
            out LocalSymbol arrayTemp)
        {
            // From ExpressionBinder::BindPtrToArray:
            // (((temp = array) != null && temp.Length > 0) ? loc = &temp[0] : loc = null)
            // NOTE: The assignment needs to be inside the EK_QUESTIONMARK. See Whidbey bug #397859.
            // We can't do loc = (... ? ... : ...) since the CLR type of &temp[0] is a managed
            // pointer and null is a UIntPtr - which confuses the JIT. We can't just convert
            // &temp[0] to UIntPtr with a conv.u instruction because then if a GC occurs between
            // the time of the cast and the assignment to the local, we're toast.

            TypeSymbol      localType       = localSymbol.Type;
            BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression);
            TypeSymbol      initializerType = initializerExpr.Type;

            arrayTemp = factory.SynthesizedLocal(initializerType);
            ArrayTypeSymbol arrayType        = (ArrayTypeSymbol)arrayTemp.Type;
            TypeSymbol      arrayElementType = arrayType.ElementType;
            int             arrayRank        = arrayType.Rank;

            // NOTE: we pin the pointer, not the array.
            Debug.Assert(!arrayTemp.IsPinned);
            Debug.Assert(localSymbol.IsPinned);

            //(temp = array)
            BoundExpression arrayTempInit = factory.AssignmentExpression(factory.Local(arrayTemp), initializerExpr);

            //(temp = array) != null
            BoundExpression notNullCheck = MakeNullCheck(factory.Syntax, arrayTempInit, BinaryOperatorKind.NotEqual);

            BoundExpression lengthCall;

            if (arrayRank == 1)
            {
                lengthCall = factory.ArrayLength(factory.Local(arrayTemp));
            }
            else
            {
                MethodSymbol lengthMethod;
                if (TryGetWellKnownTypeMember(fixedInitializer.Syntax, WellKnownMember.System_Array__get_Length, out lengthMethod))
                {
                    lengthCall = factory.Call(factory.Local(arrayTemp), lengthMethod);
                }
                else
                {
                    lengthCall = new BoundBadExpression(fixedInitializer.Syntax, LookupResultKind.NotInvocable, ImmutableArray <Symbol> .Empty, ImmutableArray.Create <BoundNode>(factory.Local(arrayTemp)), ErrorTypeSymbol.UnknownResultType);
                }
            }

            // NOTE: dev10 comment says ">", but code actually checks "!="
            //temp.Length != 0
            BoundExpression lengthCheck = factory.Binary(BinaryOperatorKind.IntNotEqual, factory.SpecialType(SpecialType.System_Boolean), lengthCall, factory.Literal(0));

            //((temp = array) != null && temp.Length != 0)
            BoundExpression condition = factory.Binary(BinaryOperatorKind.LogicalBoolAnd, factory.SpecialType(SpecialType.System_Boolean), notNullCheck, lengthCheck);

            //temp[0]
            BoundExpression firstElement = factory.ArrayAccessFirstElement(factory.Local(arrayTemp));

            // NOTE: this is a fixed statement address-of in that it's the initial value of pinned local.
            //&temp[0]
            BoundExpression firstElementAddress          = new BoundAddressOfOperator(factory.Syntax, firstElement, isFixedStatementAddressOf: true, type: new PointerTypeSymbol(arrayElementType));
            BoundExpression convertedFirstElementAddress = factory.Convert(
                localType,
                firstElementAddress,
                fixedInitializer.ElementPointerTypeConversion);

            //loc = &temp[0]
            BoundExpression consequenceAssignment = factory.AssignmentExpression(factory.Local(localSymbol), convertedFirstElementAddress);

            //loc = null
            BoundExpression alternativeAssignment = factory.AssignmentExpression(factory.Local(localSymbol), factory.Null(localType));

            //(((temp = array) != null && temp.Length != 0) ? loc = &temp[0] : loc = null)
            BoundStatement localInit = factory.ExpressionStatement(
                new BoundConditionalOperator(factory.Syntax, condition, consequenceAssignment, alternativeAssignment, ConstantValue.NotAvailable, localType));

            return(AddLocalDeclarationSequencePointIfNecessary(fixedInitializer.Syntax.Parent.Parent, localSymbol, localInit));
        }
        private BoundStatement InitializeFixedStatementArrayLocal(
            LocalSymbol localSymbol,
            BoundFixedLocalCollectionInitializer fixedInitializer,
            SyntheticBoundNodeFactory factory,
            out LocalSymbol arrayTemp)
        {
            // From ExpressionBinder::BindPtrToArray:
            // (((temp = array) != null && temp.Length > 0) ? loc = &temp[0] : loc = null)
            // NOTE: The assignment needs to be inside the EK_QUESTIONMARK. See Whidbey bug #397859.
            // We can't do loc = (... ? ... : ...) since the CLR type of &temp[0] is a managed
            // pointer and null is a UIntPtr - which confuses the JIT. We can't just convert
            // &temp[0] to UIntPtr with a conv.u instruction because then if a GC occurs between
            // the time of the cast and the assignment to the local, we're toast.

            TypeSymbol localType = localSymbol.Type;
            BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression);
            TypeSymbol initializerType = initializerExpr.Type;

            arrayTemp = factory.SynthesizedLocal(initializerType);
            ArrayTypeSymbol arrayType = (ArrayTypeSymbol)arrayTemp.Type;
            TypeSymbol arrayElementType = arrayType.ElementType;
            int arrayRank = arrayType.Rank;

            // NOTE: we pin the pointer, not the array.
            Debug.Assert(!arrayTemp.IsPinned);
            Debug.Assert(localSymbol.IsPinned);

            //(temp = array)
            BoundExpression arrayTempInit = factory.AssignmentExpression(factory.Local(arrayTemp), initializerExpr);

            //(temp = array) != null
            BoundExpression notNullCheck = MakeNullCheck(factory.Syntax, arrayTempInit, BinaryOperatorKind.NotEqual);

            BoundExpression lengthCall;

            if (arrayRank == 1)
            {
                lengthCall = factory.ArrayLength(factory.Local(arrayTemp));
            }
            else
            {
                MethodSymbol lengthMethod;
                if (TryGetWellKnownTypeMember(fixedInitializer.Syntax, WellKnownMember.System_Array__get_Length, out lengthMethod))
                {
                    lengthCall = factory.Call(factory.Local(arrayTemp), lengthMethod);
                }
                else
                {
                    lengthCall = new BoundBadExpression(fixedInitializer.Syntax, LookupResultKind.NotInvocable, ImmutableArray<Symbol>.Empty, ImmutableArray.Create<BoundNode>(factory.Local(arrayTemp)), ErrorTypeSymbol.UnknownResultType);
                }
            }

            // NOTE: dev10 comment says ">", but code actually checks "!="
            //temp.Length != 0
            BoundExpression lengthCheck = factory.Binary(BinaryOperatorKind.IntNotEqual, factory.SpecialType(SpecialType.System_Boolean), lengthCall, factory.Literal(0));

            //((temp = array) != null && temp.Length != 0)
            BoundExpression condition = factory.Binary(BinaryOperatorKind.LogicalBoolAnd, factory.SpecialType(SpecialType.System_Boolean), notNullCheck, lengthCheck);

            //temp[0]
            BoundExpression firstElement = factory.ArrayAccessFirstElement(factory.Local(arrayTemp));

            // NOTE: this is a fixed statement address-of in that it's the initial value of pinned local.
            //&temp[0]
            BoundExpression firstElementAddress = new BoundAddressOfOperator(factory.Syntax, firstElement, isFixedStatementAddressOf: true, type: new PointerTypeSymbol(arrayElementType));
            BoundExpression convertedFirstElementAddress = factory.Convert(
                localType,
                firstElementAddress, 
                fixedInitializer.ElementPointerTypeConversion);

            //loc = &temp[0]
            BoundExpression consequenceAssignment = factory.AssignmentExpression(factory.Local(localSymbol), convertedFirstElementAddress);

            //loc = null
            BoundExpression alternativeAssignment = factory.AssignmentExpression(factory.Local(localSymbol), factory.Null(localType));

            //(((temp = array) != null && temp.Length != 0) ? loc = &temp[0] : loc = null)
            BoundStatement localInit = factory.ExpressionStatement(
                new BoundConditionalOperator(factory.Syntax, condition, consequenceAssignment, alternativeAssignment, ConstantValue.NotAvailable, localType));

            return AddLocalDeclarationSequencePointIfNecessary(fixedInitializer.Syntax.Parent.Parent, localSymbol, localInit);
        }
        private BoundStatement InitializeFixedStatementStringLocal(
            LocalSymbol localSymbol,
            BoundFixedLocalCollectionInitializer fixedInitializer,
            SyntheticBoundNodeFactory factory,
            out LocalSymbol stringTemp,
            out LocalSymbol localToClear)
        {
            TypeSymbol localType = localSymbol.Type;
            BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression);
            TypeSymbol initializerType = initializerExpr.Type;

            // intervening parens may have been skipped by the binder; find the declarator
            VariableDeclaratorSyntax declarator = fixedInitializer.Syntax.FirstAncestorOrSelf<VariableDeclaratorSyntax>();
            Debug.Assert(declarator != null);

            stringTemp = factory.SynthesizedLocal(initializerType, syntax: declarator, isPinned: true, kind: SynthesizedLocalKind.FixedString);

            // NOTE: we pin the string, not the pointer.
            Debug.Assert(stringTemp.IsPinned);
            Debug.Assert(!localSymbol.IsPinned);

            BoundStatement stringTempInit = factory.Assignment(factory.Local(stringTemp), initializerExpr);

            var convertedStringTemp = factory.Convert(
                localType,
                factory.Local(stringTemp),
                fixedInitializer.ElementPointerTypeConversion);

            BoundStatement localInit = AddLocalDeclarationSequencePointIfNecessary(declarator, localSymbol, 
                factory.Assignment(factory.Local(localSymbol), convertedStringTemp));

            BoundExpression notNullCheck = MakeNullCheck(factory.Syntax, factory.Local(stringTemp), BinaryOperatorKind.NotEqual);
            BoundExpression helperCall;

            MethodSymbol offsetMethod;
            if (TryGetWellKnownTypeMember(fixedInitializer.Syntax, WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__get_OffsetToStringData, out offsetMethod))
            {
                helperCall = factory.Call(receiver: null, method: offsetMethod);
            }
            else
            {
                helperCall = new BoundBadExpression(fixedInitializer.Syntax, LookupResultKind.NotInvocable, ImmutableArray<Symbol>.Empty, ImmutableArray<BoundNode>.Empty, ErrorTypeSymbol.UnknownResultType);
            }

            BoundExpression addition = factory.Binary(BinaryOperatorKind.PointerAndIntAddition, localType, factory.Local(localSymbol), helperCall);
            BoundStatement conditionalAdd = factory.If(notNullCheck, factory.Assignment(factory.Local(localSymbol), addition));

            localToClear = stringTemp;
            return factory.Block(stringTempInit, localInit, conditionalAdd);
        }
コード例 #9
0
        public override BoundNode VisitLoweredConditionalAccess(BoundLoweredConditionalAccess node)
        {
            var receiverRefKind = ReceiverSpillRefKind(node.Receiver);

            BoundSpillSequenceBuilder receiverBuilder = null;
            var receiver = VisitExpression(ref receiverBuilder, node.Receiver);

            BoundSpillSequenceBuilder whenNotNullBuilder = null;
            var whenNotNull = VisitExpression(ref whenNotNullBuilder, node.WhenNotNull);

            BoundSpillSequenceBuilder whenNullBuilder = null;
            var whenNullOpt = VisitExpression(ref whenNullBuilder, node.WhenNullOpt);

            if (whenNotNullBuilder == null && whenNullBuilder == null)
            {
                return(UpdateExpression(receiverBuilder, node.Update(receiver, node.HasValueMethodOpt, whenNotNull, whenNullOpt, node.Id, node.Type)));
            }

            if (receiverBuilder == null)
            {
                receiverBuilder = new BoundSpillSequenceBuilder();
            }
            if (whenNotNullBuilder == null)
            {
                whenNotNullBuilder = new BoundSpillSequenceBuilder();
            }
            if (whenNullBuilder == null)
            {
                whenNullBuilder = new BoundSpillSequenceBuilder();
            }


            BoundExpression condition;

            if (receiver.Type.IsReferenceType || receiver.Type.IsValueType || receiverRefKind == RefKind.None)
            {
                // spill to a clone
                receiver = Spill(receiverBuilder, receiver, RefKind.None);
                var hasValueOpt = node.HasValueMethodOpt;

                if (hasValueOpt == null)
                {
                    condition = _F.ObjectNotEqual(
                        _F.Convert(_F.SpecialType(SpecialType.System_Object), receiver),
                        _F.Null(_F.SpecialType(SpecialType.System_Object)));
                }
                else
                {
                    condition = _F.Call(receiver, hasValueOpt);
                }
            }
            else
            {
                Debug.Assert(node.HasValueMethodOpt == null);
                receiver = Spill(receiverBuilder, receiver, RefKind.Ref);

                var clone = _F.SynthesizedLocal(receiver.Type, _F.Syntax, refKind: RefKind.None, kind: SynthesizedLocalKind.Spill);
                receiverBuilder.AddLocal(clone);

                //  (object)default(T) != null
                var isNotClass = _F.ObjectNotEqual(
                    _F.Convert(_F.SpecialType(SpecialType.System_Object), _F.Default(receiver.Type)),
                    _F.Null(_F.SpecialType(SpecialType.System_Object)));

                // isNotCalss || {clone = receiver; (object)clone != null}
                condition = _F.LogicalOr(
                    isNotClass,
                    _F.MakeSequence(
                        _F.AssignmentExpression(_F.Local(clone), receiver),
                        _F.ObjectNotEqual(
                            _F.Convert(_F.SpecialType(SpecialType.System_Object), _F.Local(clone)),
                            _F.Null(_F.SpecialType(SpecialType.System_Object))))
                    );

                receiver = _F.ComplexConditionalReceiver(receiver, _F.Local(clone));
            }

            if (node.Type.IsVoidType())
            {
                var whenNotNullStatement = UpdateStatement(whenNotNullBuilder, _F.ExpressionStatement(whenNotNull));
                whenNotNullStatement = ConditionalReceiverReplacer.Replace(whenNotNullStatement, receiver, node.Id, RecursionDepth);

                Debug.Assert(whenNullOpt == null || !LocalRewriter.ReadIsSideeffecting(whenNullOpt));

                receiverBuilder.AddStatement(_F.If(condition, whenNotNullStatement));

                return(receiverBuilder.Update(_F.Default(node.Type)));
            }
            else
            {
                var tmp = _F.SynthesizedLocal(node.Type, kind: SynthesizedLocalKind.Spill, syntax: _F.Syntax);
                var whenNotNullStatement = UpdateStatement(whenNotNullBuilder, _F.Assignment(_F.Local(tmp), whenNotNull));
                whenNotNullStatement = ConditionalReceiverReplacer.Replace(whenNotNullStatement, receiver, node.Id, RecursionDepth);

                whenNullOpt = whenNullOpt ?? _F.Default(node.Type);

                receiverBuilder.AddLocal(tmp);
                receiverBuilder.AddStatement(
                    _F.If(condition,
                          whenNotNullStatement,
                          UpdateStatement(whenNullBuilder, _F.Assignment(_F.Local(tmp), whenNullOpt))));

                return(receiverBuilder.Update(_F.Local(tmp)));
            }
        }
コード例 #10
0
        /// <summary>
        /// <![CDATA[
        /// fixed(int* ptr = arr){ ... }    == becomes ===>
        ///
        /// pinned int[] pinnedTemp = arr;         // pinning managed ref
        /// int* ptr = pinnedTemp != null && pinnedTemp.Length != 0
        ///                (int*)&pinnedTemp[0]:   // unsafe cast to unmanaged ptr
        ///                0;
        ///   . . .
        ///   ]]>
        /// </summary>
        private BoundStatement InitializeFixedStatementArrayLocal(
            BoundLocalDeclaration localDecl,
            LocalSymbol localSymbol,
            BoundFixedLocalCollectionInitializer fixedInitializer,
            SyntheticBoundNodeFactory factory,
            out LocalSymbol pinnedTemp)
        {
            TypeSymbol      localType       = localSymbol.Type;
            BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression);
            TypeSymbol      initializerType = initializerExpr.Type;

            pinnedTemp = factory.SynthesizedLocal(initializerType, isPinned: true);
            ArrayTypeSymbol     arrayType        = (ArrayTypeSymbol)pinnedTemp.Type;
            TypeWithAnnotations arrayElementType = arrayType.ElementTypeWithAnnotations;

            // NOTE: we pin the array, not the pointer.
            Debug.Assert(pinnedTemp.IsPinned);
            Debug.Assert(!localSymbol.IsPinned);

            //(pinnedTemp = array)
            BoundExpression arrayTempInit = factory.AssignmentExpression(factory.Local(pinnedTemp), initializerExpr);

            //(pinnedTemp = array) != null
            BoundExpression notNullCheck = MakeNullCheck(factory.Syntax, arrayTempInit, BinaryOperatorKind.NotEqual);

            BoundExpression lengthCall;

            if (arrayType.IsSZArray)
            {
                lengthCall = factory.ArrayLength(factory.Local(pinnedTemp));
            }
            else
            {
                MethodSymbol lengthMethod;
                if (TryGetWellKnownTypeMember(fixedInitializer.Syntax, WellKnownMember.System_Array__get_Length, out lengthMethod))
                {
                    lengthCall = factory.Call(factory.Local(pinnedTemp), lengthMethod);
                }
                else
                {
                    lengthCall = new BoundBadExpression(fixedInitializer.Syntax, LookupResultKind.NotInvocable, ImmutableArray <Symbol> .Empty, ImmutableArray.Create <BoundExpression>(factory.Local(pinnedTemp)), ErrorTypeSymbol.UnknownResultType);
                }
            }

            // NOTE: dev10 comment says ">", but code actually checks "!="
            //temp.Length != 0
            BoundExpression lengthCheck = factory.Binary(BinaryOperatorKind.IntNotEqual, factory.SpecialType(SpecialType.System_Boolean), lengthCall, factory.Literal(0));

            //((temp = array) != null && temp.Length != 0)
            BoundExpression condition = factory.Binary(BinaryOperatorKind.LogicalBoolAnd, factory.SpecialType(SpecialType.System_Boolean), notNullCheck, lengthCheck);

            //temp[0]
            BoundExpression firstElement = factory.ArrayAccessFirstElement(factory.Local(pinnedTemp));

            // NOTE: this is a fixed statement address-of in that it's the initial value of the pointer.
            //&temp[0]
            BoundExpression firstElementAddress          = new BoundAddressOfOperator(factory.Syntax, firstElement, type: new PointerTypeSymbol(arrayElementType));
            BoundExpression convertedFirstElementAddress = factory.Convert(
                localType,
                firstElementAddress,
                fixedInitializer.ElementPointerTypeConversion);

            //loc = &temp[0]
            BoundExpression consequenceAssignment = factory.AssignmentExpression(factory.Local(localSymbol), convertedFirstElementAddress);

            //loc = null
            BoundExpression alternativeAssignment = factory.AssignmentExpression(factory.Local(localSymbol), factory.Null(localType));

            //(((temp = array) != null && temp.Length != 0) ? loc = &temp[0] : loc = null)
            BoundStatement localInit = factory.ExpressionStatement(
                new BoundConditionalOperator(factory.Syntax, false, condition, consequenceAssignment, alternativeAssignment, ConstantValue.NotAvailable, localType));

            return(InstrumentLocalDeclarationIfNecessary(localDecl, localSymbol, localInit));
        }
コード例 #11
0
        /// <summary>
        /// <![CDATA[
        /// fixed(int* ptr = &v){ ... }    == becomes ===>
        ///
        /// pinned ref int pinnedTemp = ref v;    // pinning managed ref
        /// int* ptr = (int*)&pinnedTemp;         // unsafe cast to unmanaged ptr
        ///   . . .
        /// ]]>
        /// </summary>
        private BoundStatement InitializeFixedStatementGetPinnable(
            BoundLocalDeclaration localDecl,
            LocalSymbol localSymbol,
            BoundFixedLocalCollectionInitializer fixedInitializer,
            SyntheticBoundNodeFactory factory,
            out LocalSymbol pinnedTemp)
        {
            TypeSymbol      localType       = localSymbol.Type;
            BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression);

            var initializerType   = initializerExpr.Type;
            var initializerSyntax = initializerExpr.Syntax;
            var getPinnableMethod = fixedInitializer.GetPinnableOpt;

            // intervening parens may have been skipped by the binder; find the declarator
            VariableDeclaratorSyntax declarator = fixedInitializer.Syntax.FirstAncestorOrSelf <VariableDeclaratorSyntax>();

            Debug.Assert(declarator != null);

            // pinned ref int pinnedTemp
            pinnedTemp = factory.SynthesizedLocal(
                getPinnableMethod.ReturnType,
                syntax: declarator,
                isPinned: true,
                //NOTE: different from the array and string cases
                //      RefReadOnly to allow referring to readonly variables. (technically we only "read" through the temp anyways)
                refKind: RefKind.RefReadOnly,
                kind: SynthesizedLocalKind.FixedReference);

            BoundExpression callReceiver;
            int             currentConditionalAccessID = 0;

            bool needNullCheck = !initializerType.IsValueType;

            if (needNullCheck)
            {
                currentConditionalAccessID = ++_currentConditionalAccessID;
                callReceiver = new BoundConditionalReceiver(
                    initializerSyntax,
                    currentConditionalAccessID,
                    initializerType);
            }
            else
            {
                callReceiver = initializerExpr;
            }

            // .GetPinnable()
            var getPinnableCall = getPinnableMethod.IsStatic ?
                                  factory.Call(null, getPinnableMethod, callReceiver) :
                                  factory.Call(callReceiver, getPinnableMethod);

            // temp =ref .GetPinnable()
            var tempAssignment = factory.AssignmentExpression(
                factory.Local(pinnedTemp),
                getPinnableCall,
                isRef: true);

            // &pinnedTemp
            var addr = new BoundAddressOfOperator(
                factory.Syntax,
                factory.Local(pinnedTemp),
                type: fixedInitializer.ElementPointerType);

            // (int*)&pinnedTemp
            var pointerValue = factory.Convert(
                localType,
                addr,
                fixedInitializer.ElementPointerTypeConversion);

            // {pinnedTemp =ref .GetPinnable(), (int*)&pinnedTemp}
            BoundExpression pinAndGetPtr = factory.Sequence(
                locals: ImmutableArray <LocalSymbol> .Empty,
                sideEffects: ImmutableArray.Create <BoundExpression>(tempAssignment),
                result: pointerValue);

            if (needNullCheck)
            {
                // initializer?.{temp =ref .GetPinnable(), (int*)&pinnedTemp} ?? default;
                pinAndGetPtr = new BoundLoweredConditionalAccess(
                    initializerSyntax,
                    initializerExpr,
                    hasValueMethodOpt: null,
                    whenNotNull: pinAndGetPtr,
                    whenNullOpt: null, // just return default(T*)
                    currentConditionalAccessID,
                    localType);
            }

            // ptr = initializer?.{temp =ref .GetPinnable(), (int*)&pinnedTemp} ?? default;
            BoundStatement localInit = InstrumentLocalDeclarationIfNecessary(localDecl, localSymbol, factory.Assignment(factory.Local(localSymbol), pinAndGetPtr));

            return(localInit);
        }
コード例 #12
0
            /// <summary>
            /// Return the side-effect expression corresponding to an evaluation.
            /// </summary>
            protected BoundExpression LowerEvaluation(BoundDagEvaluation evaluation)
            {
                BoundExpression input = _tempAllocator.GetTemp(evaluation.Input);

                switch (evaluation)
                {
                case BoundDagFieldEvaluation f:
                {
                    FieldSymbol     field      = f.Field;
                    var             outputTemp = new BoundDagTemp(f.Syntax, field.Type.TypeSymbol, f, index: 0);
                    BoundExpression output     = _tempAllocator.GetTemp(outputTemp);
                    BoundExpression access     = _localRewriter.MakeFieldAccess(f.Syntax, input, field, null, LookupResultKind.Viable, field.Type.TypeSymbol);
                    access.WasCompilerGenerated = true;
                    return(_factory.AssignmentExpression(output, access));
                }

                case BoundDagPropertyEvaluation p:
                {
                    PropertySymbol  property   = p.Property;
                    var             outputTemp = new BoundDagTemp(p.Syntax, property.Type.TypeSymbol, p, index: 0);
                    BoundExpression output     = _tempAllocator.GetTemp(outputTemp);
                    return(_factory.AssignmentExpression(output, _factory.Property(input, property)));
                }

                case BoundDagDeconstructEvaluation d:
                {
                    MethodSymbol method         = d.DeconstructMethod;
                    var          refKindBuilder = ArrayBuilder <RefKind> .GetInstance();

                    var argBuilder = ArrayBuilder <BoundExpression> .GetInstance();

                    BoundExpression receiver;
                    void addArg(RefKind refKind, BoundExpression expression)
                    {
                        refKindBuilder.Add(refKind);
                        argBuilder.Add(expression);
                    }

                    Debug.Assert(method.Name == WellKnownMemberNames.DeconstructMethodName);
                    int extensionExtra;
                    if (method.IsStatic)
                    {
                        Debug.Assert(method.IsExtensionMethod);
                        receiver = _factory.Type(method.ContainingType);
                        addArg(method.ParameterRefKinds[0], input);
                        extensionExtra = 1;
                    }
                    else
                    {
                        receiver       = input;
                        extensionExtra = 0;
                    }

                    for (int i = extensionExtra; i < method.ParameterCount; i++)
                    {
                        ParameterSymbol parameter = method.Parameters[i];
                        Debug.Assert(parameter.RefKind == RefKind.Out);
                        var outputTemp = new BoundDagTemp(d.Syntax, parameter.Type.TypeSymbol, d, i - extensionExtra);
                        addArg(RefKind.Out, _tempAllocator.GetTemp(outputTemp));
                    }

                    return(_factory.Call(receiver, method, refKindBuilder.ToImmutableAndFree(), argBuilder.ToImmutableAndFree()));
                }

                case BoundDagTypeEvaluation t:
                {
                    TypeSymbol inputType = input.Type;
                    if (inputType.IsDynamic() || inputType.ContainsTypeParameter())
                    {
                        inputType = _factory.SpecialType(SpecialType.System_Object);
                    }

                    TypeSymbol               type               = t.Type;
                    var                      outputTemp         = new BoundDagTemp(t.Syntax, type, t, index: 0);
                    BoundExpression          output             = _tempAllocator.GetTemp(outputTemp);
                    HashSet <DiagnosticInfo> useSiteDiagnostics = null;
                    Conversion               conversion         = _factory.Compilation.Conversions.ClassifyBuiltInConversion(inputType, output.Type, ref useSiteDiagnostics);
                    _localRewriter._diagnostics.Add(t.Syntax, useSiteDiagnostics);
                    BoundExpression evaluated;
                    if (conversion.Exists)
                    {
                        if (conversion.Kind == ConversionKind.ExplicitNullable &&
                            inputType.GetNullableUnderlyingType().Equals(output.Type, TypeCompareKind.AllIgnoreOptions) &&
                            _localRewriter.TryGetNullableMethod(t.Syntax, inputType, SpecialMember.System_Nullable_T_GetValueOrDefault, out MethodSymbol getValueOrDefault))
                        {
                            // As a special case, since the null test has already been done we can use Nullable<T>.GetValueOrDefault
                            evaluated = _factory.Call(input, getValueOrDefault);
                        }
                        else
                        {
                            evaluated = _factory.Convert(type, input, conversion);
                        }
                    }
                    else
                    {
                        evaluated = _factory.As(input, type);
                    }

                    return(_factory.AssignmentExpression(output, evaluated));
                }

                case BoundDagIndexEvaluation e:
                {
                    // This is an evaluation of an indexed property with a constant int value.
                    // The input type must be ITuple, and the property must be a property of ITuple.
                    Debug.Assert(e.Property.ContainingSymbol.Equals(input.Type));
                    Debug.Assert(e.Property.GetMethod.ParameterCount == 1);
                    Debug.Assert(e.Property.GetMethod.Parameters[0].Type.SpecialType == SpecialType.System_Int32);
                    TypeSymbol      type       = e.Property.GetMethod.ReturnType.TypeSymbol;
                    var             outputTemp = new BoundDagTemp(e.Syntax, type, e, index: 0);
                    BoundExpression output     = _tempAllocator.GetTemp(outputTemp);
                    return(_factory.AssignmentExpression(output, _factory.Call(input, e.Property.GetMethod, _factory.Literal(e.Index))));
                }

                default:
                    throw ExceptionUtilities.UnexpectedValue(evaluation);
                }
            }
コード例 #13
0
            private void LowerDecisionTree(DecisionTree.ByType byType)
            {
                var inputConstant = byType.Expression.ConstantValue;

                if (inputConstant != null)
                {
                    if (inputConstant.IsNull)
                    {
                        // input is the constant null
                        LowerDecisionTree(byType.Expression, byType.WhenNull);
                        if (byType.WhenNull?.MatchIsComplete != true)
                        {
                            LowerDecisionTree(byType.Expression, byType.Default);
                        }
                    }
                    else
                    {
                        // input is a non-null constant
                        foreach (var kvp in byType.TypeAndDecision)
                        {
                            LowerDecisionTree(byType.Expression, kvp.Value);
                            if (kvp.Value.MatchIsComplete)
                            {
                                return;
                            }
                        }

                        LowerDecisionTree(byType.Expression, byType.Default);
                    }
                }
                else
                {
                    var defaultLabel = _factory.GenerateLabel("byTypeDefault");

                    // input is not a constant
                    if (byType.Type.CanContainNull())
                    {
                        // first test for null
                        var             notNullLabel    = _factory.GenerateLabel("notNull");
                        var             inputExpression = byType.Expression;
                        var             objectType      = _factory.SpecialType(SpecialType.System_Object);
                        var             nullValue       = _factory.Null(objectType);
                        BoundExpression notNull         = byType.Type.IsNullableType()
                            ? _localRewriter.RewriteNullableNullEquality(_factory.Syntax, BinaryOperatorKind.NullableNullNotEqual, byType.Expression, nullValue, _factory.SpecialType(SpecialType.System_Boolean))
                            : _factory.ObjectNotEqual(nullValue, _factory.Convert(objectType, byType.Expression));
                        _loweredDecisionTree.Add(_factory.ConditionalGoto(notNull, notNullLabel, true));
                        LowerDecisionTree(byType.Expression, byType.WhenNull);
                        if (byType.WhenNull?.MatchIsComplete != true)
                        {
                            _loweredDecisionTree.Add(_factory.Goto(defaultLabel));
                        }

                        _loweredDecisionTree.Add(_factory.Label(notNullLabel));
                    }
                    else
                    {
                        Debug.Assert(byType.WhenNull == null);
                    }

                    foreach (var td in byType.TypeAndDecision)
                    {
                        // then test for each type, sequentially
                        var type        = td.Key;
                        var decision    = td.Value;
                        var failLabel   = _factory.GenerateLabel("failedDecision");
                        var testAndCopy = TypeTestAndCopyToTemp(byType.Expression, decision.Expression);
                        _loweredDecisionTree.Add(_factory.ConditionalGoto(testAndCopy, failLabel, false));
                        LowerDecisionTree(decision.Expression, decision);
                        _loweredDecisionTree.Add(_factory.Label(failLabel));
                    }

                    // finally, the default for when no type matches
                    _loweredDecisionTree.Add(_factory.Label(defaultLabel));
                    LowerDecisionTree(byType.Expression, byType.Default);
                }
            }
コード例 #14
0
            protected BoundExpression LowerEvaluation(BoundDagEvaluation evaluation)
            {
                BoundExpression input = _tempAllocator.GetTemp(evaluation.Input);

                switch (evaluation)
                {
                case BoundDagFieldEvaluation f:
                {
                    FieldSymbol     field      = f.Field;
                    var             outputTemp = new BoundDagTemp(f.Syntax, field.Type, f);
                    BoundExpression output     = _tempAllocator.GetTemp(outputTemp);
                    BoundExpression access     = _localRewriter.MakeFieldAccess(f.Syntax, input, field, null, LookupResultKind.Viable, field.Type);
                    access.WasCompilerGenerated = true;
                    return(_factory.AssignmentExpression(output, access));
                }

                case BoundDagPropertyEvaluation p:
                {
                    PropertySymbol  property   = p.Property;
                    var             outputTemp = new BoundDagTemp(p.Syntax, property.Type, p);
                    BoundExpression output     = _tempAllocator.GetTemp(outputTemp);
                    return(_factory.AssignmentExpression(output, _localRewriter.MakePropertyAccess(_factory.Syntax, input, property, LookupResultKind.Viable, property.Type, isLeftOfAssignment: false)));
                }

                case BoundDagDeconstructEvaluation d:
                {
                    MethodSymbol method         = d.DeconstructMethod;
                    var          refKindBuilder = ArrayBuilder <RefKind> .GetInstance();

                    var argBuilder = ArrayBuilder <BoundExpression> .GetInstance();

                    BoundExpression receiver;
                    void addArg(RefKind refKind, BoundExpression expression)
                    {
                        refKindBuilder.Add(refKind);
                        argBuilder.Add(expression);
                    }

                    Debug.Assert(method.Name == WellKnownMemberNames.DeconstructMethodName);
                    int extensionExtra;
                    if (method.IsStatic)
                    {
                        Debug.Assert(method.IsExtensionMethod);
                        receiver = _factory.Type(method.ContainingType);
                        addArg(method.ParameterRefKinds[0], input);
                        extensionExtra = 1;
                    }
                    else
                    {
                        receiver       = input;
                        extensionExtra = 0;
                    }

                    for (int i = extensionExtra; i < method.ParameterCount; i++)
                    {
                        ParameterSymbol parameter = method.Parameters[i];
                        Debug.Assert(parameter.RefKind == RefKind.Out);
                        var outputTemp = new BoundDagTemp(d.Syntax, parameter.Type, d, i - extensionExtra);
                        addArg(RefKind.Out, _tempAllocator.GetTemp(outputTemp));
                    }

                    return(_factory.Call(receiver, method, refKindBuilder.ToImmutableAndFree(), argBuilder.ToImmutableAndFree()));
                }

                case BoundDagTypeEvaluation t:
                {
                    TypeSymbol inputType = input.Type;
                    Debug.Assert(inputType is { });
                    if (inputType.IsDynamic())
                    {
                        // Avoid using dynamic conversions for pattern-matching.
                        inputType = _factory.SpecialType(SpecialType.System_Object);
                        input     = _factory.Convert(inputType, input);
                    }

                    TypeSymbol      type       = t.Type;
                    var             outputTemp = new BoundDagTemp(t.Syntax, type, t);
                    BoundExpression output     = _tempAllocator.GetTemp(outputTemp);
                    CompoundUseSiteInfo <AssemblySymbol> useSiteInfo = _localRewriter.GetNewCompoundUseSiteInfo();
                    Conversion conversion = _factory.Compilation.Conversions.ClassifyBuiltInConversion(inputType, output.Type, isChecked: false, ref useSiteInfo);

                    Debug.Assert(!conversion.IsUserDefined);
                    _localRewriter._diagnostics.Add(t.Syntax, useSiteInfo);
                    BoundExpression evaluated;
                    if (conversion.Exists)
                    {
                        if (conversion.Kind == ConversionKind.ExplicitNullable &&
                            inputType.GetNullableUnderlyingType().Equals(output.Type, TypeCompareKind.AllIgnoreOptions) &&
                            _localRewriter.TryGetNullableMethod(t.Syntax, inputType, SpecialMember.System_Nullable_T_GetValueOrDefault, out MethodSymbol getValueOrDefault))
                        {
                            // As a special case, since the null test has already been done we can use Nullable<T>.GetValueOrDefault
                            evaluated = _factory.Call(input, getValueOrDefault);
                        }
                        else
                        {
                            evaluated = _factory.Convert(type, input, conversion);
                        }
                    }
                    else
                    {
                        evaluated = _factory.As(input, type);
                    }

                    return(_factory.AssignmentExpression(output, evaluated));
                }
コード例 #15
0
            // For switch statements, we have an option of completely rewriting the switch header
            // and switch sections into simpler constructs, i.e. we can rewrite the switch header
            // using bound conditional goto statements and the rewrite the switch sections into
            // bound labeled statements.
            //
            // However, all the logic for emitting the switch jump tables is language agnostic
            // and includes IL optimizations. Hence we delay the switch jump table generation
            // till the emit phase. This way we also get additional benefit of sharing this code
            // between both VB and C# compilers.
            //
            // For string switch statements, we need to determine if we are generating a hash
            // table based jump table or a non hash jump table, i.e. linear string comparisons
            // with each case label. We use the Dev10 Heuristic to determine this
            // (see SwitchStringJumpTableEmitter.ShouldGenerateHashTableSwitch() for details).
            // If we are generating a hash table based jump table, we use a simple
            // hash function to hash the string constants corresponding to the case labels.
            // See SwitchStringJumpTableEmitter.ComputeStringHash().
            // We need to emit this same function to compute the hash value into the compiler generated
            // <PrivateImplementationDetails> class.
            // If we have at least one string switch statement in a module that needs a
            // hash table based jump table, we generate a single public string hash synthesized method
            // that is shared across the module.
            private void LowerBasicSwitch(DecisionTree.ByValue byValue)
            {
                var switchSections = ArrayBuilder <BoundSwitchSection> .GetInstance();

                var noValueMatches       = _factory.GenerateLabel("noValueMatches");
                var underlyingSwitchType = byValue.Type.IsEnumType() ? byValue.Type.GetEnumUnderlyingType() : byValue.Type;

                foreach (var vd in byValue.ValueAndDecision)
                {
                    var value              = vd.Key;
                    var decision           = vd.Value;
                    var constantValue      = ConstantValue.Create(value, underlyingSwitchType.SpecialType);
                    var constantExpression = new BoundLiteral(_factory.Syntax, constantValue, underlyingSwitchType);
                    var label              = _factory.GenerateLabel("case+" + value);
                    var switchLabel        = new BoundSwitchLabel(_factory.Syntax, label, constantExpression, constantValue);
                    var forValue           = ArrayBuilder <BoundStatement> .GetInstance();

                    LowerDecisionTree(byValue.Expression, decision, forValue);
                    if (!decision.MatchIsComplete)
                    {
                        forValue.Add(_factory.Goto(noValueMatches));
                    }

                    var section = new BoundSwitchSection(_factory.Syntax, ImmutableArray.Create(switchLabel), forValue.ToImmutableAndFree());
                    switchSections.Add(section);
                }

                var          rewrittenSections = switchSections.ToImmutableAndFree();
                MethodSymbol stringEquality    = null;

                if (underlyingSwitchType.SpecialType == SpecialType.System_String)
                {
                    LocalRewriter.EnsureStringHashFunction(rewrittenSections, _factory.Syntax);
                    stringEquality = LocalRewriter.GetSpecialTypeMethod(_factory.Syntax, SpecialMember.System_String__op_Equality);
                }

                // The BoundSwitchStatement requires a constant target when there are no sections, so we accomodate that here.
                var constantTarget  = rewrittenSections.IsEmpty ? noValueMatches : null;
                var switchStatement = new BoundSwitchStatement(
                    _factory.Syntax, null, _factory.Convert(underlyingSwitchType, byValue.Expression),
                    constantTarget,
                    ImmutableArray <LocalSymbol> .Empty, ImmutableArray <LocalFunctionSymbol> .Empty,
                    rewrittenSections, noValueMatches, stringEquality);

                // The bound switch statement implicitly defines the label noValueMatches at the end, so we do not add it explicitly.

                switch (underlyingSwitchType.SpecialType)
                {
                case SpecialType.System_Boolean:
                    // boolean switch is handled in LowerBooleanSwitch, not here.
                    throw ExceptionUtilities.Unreachable;

                case SpecialType.System_String:
                case SpecialType.System_Byte:
                case SpecialType.System_Char:
                case SpecialType.System_Int16:
                case SpecialType.System_Int32:
                case SpecialType.System_Int64:
                case SpecialType.System_SByte:
                case SpecialType.System_UInt16:
                case SpecialType.System_UInt32:
                case SpecialType.System_UInt64:
                {
                    // emit knows how to efficiently generate code for these kinds of switches.
                    _loweredDecisionTree.Add(switchStatement);
                    break;
                }

                default:
                {
                    // other types, such as float, double, and decimal, are not currently
                    // handled by emit and must be lowered here.
                    _loweredDecisionTree.Add(LowerNonprimitiveSwitch(switchStatement));
                    break;
                }
                }

                LowerDecisionTree(byValue.Expression, byValue.Default);
            }