Example #1
0
            /// <summary>
            /// Produce assignment of the input expression. This method is also responsible for assigning
            /// variables for some pattern-matching temps that can be shared with user variables.
            /// </summary>
            protected BoundDecisionDag ShareTempsAndEvaluateInput(
                BoundExpression loweredInput,
                BoundDecisionDag decisionDag,
                Action <BoundExpression> addCode,
                out BoundExpression savedInputExpression)
            {
                var inputDagTemp = BoundDagTemp.ForOriginalInput(loweredInput);

                if ((loweredInput.Kind == BoundKind.Local || loweredInput.Kind == BoundKind.Parameter) &&
                    loweredInput.GetRefKind() == RefKind.None)
                {
                    // If we're switching on a local variable and there is no when clause (checked by the caller),
                    // we assume the value of the local variable does not change during the execution of the
                    // decision automaton and we just reuse the local variable when we need the input expression.
                    // It is possible for this assumption to be violated by a side-effecting Deconstruct that
                    // modifies the local variable which has been captured in a lambda. Since the language assumes
                    // that functions called by pattern-matching are idempotent and not side-effecting, we feel
                    // justified in taking this assumption in the compiler too.
                    bool tempAssigned = _tempAllocator.TrySetTemp(inputDagTemp, loweredInput);
                    Debug.Assert(tempAssigned);
                }

                foreach (BoundDecisionDagNode node in decisionDag.TopologicallySortedNodes)
                {
                    if (node is BoundWhenDecisionDagNode w)
                    {
                        // We share a slot for a user-declared pattern-matching variable with a pattern temp if there
                        // is no user-written when-clause that could modify the variable before the matching
                        // automaton is done with it (checked by the caller).
                        foreach (BoundPatternBinding binding in w.Bindings)
                        {
                            if (binding.VariableAccess is BoundLocal l)
                            {
                                Debug.Assert(l.LocalSymbol.DeclarationKind == LocalDeclarationKind.PatternVariable);
                                _ = _tempAllocator.TrySetTemp(binding.TempContainingValue, binding.VariableAccess);
                            }
                        }
                    }
                }

                if (loweredInput.Type.IsTupleType &&
                    loweredInput.Syntax.Kind() == SyntaxKind.TupleExpression &&
                    loweredInput is BoundObjectCreationExpression expr &&
                    !decisionDag.TopologicallySortedNodes.Any(n => usesOriginalInput(n)))
                {
                    // If the switch governing expression is a tuple literal whose whole value is not used anywhere,
                    // (though perhaps its component parts are used), then we can save the component parts
                    // and assign them into temps (or perhaps user variables) to avoid the creation of
                    // the tuple altogether.
                    decisionDag = RewriteTupleInput(decisionDag, expr, addCode, out savedInputExpression);
                }
Example #2
0
        /// <summary>
        /// Generates a lowered form of the assignment operator for the given left and right sub-expressions.
        /// Left and right sub-expressions must be in lowered form.
        /// </summary>
        private BoundExpression MakeStaticAssignmentOperator(
            SyntaxNode syntax,
            BoundExpression rewrittenLeft,
            BoundExpression rewrittenRight,
            bool isRef,
            TypeSymbol type,
            bool used)
        {
            switch (rewrittenLeft.Kind)
            {
            case BoundKind.DynamicIndexerAccess:
            case BoundKind.DynamicMemberAccess:
                throw ExceptionUtilities.UnexpectedValue(rewrittenLeft.Kind);

            case BoundKind.PropertyAccess:
            {
                Debug.Assert(!isRef);
                BoundPropertyAccess propertyAccess    = (BoundPropertyAccess)rewrittenLeft;
                BoundExpression?    rewrittenReceiver = propertyAccess.ReceiverOpt;
                PropertySymbol      property          = propertyAccess.PropertySymbol;
                Debug.Assert(!property.IsIndexer);
                return(MakePropertyAssignment(
                           syntax,
                           rewrittenReceiver,
                           property,
                           ImmutableArray <BoundExpression> .Empty,
                           default(ImmutableArray <RefKind>),
                           false,
                           default(ImmutableArray <int>),
                           rewrittenRight,
                           type,
                           used));
            }

            case BoundKind.IndexerAccess:
            {
                Debug.Assert(!isRef);
                BoundIndexerAccess indexerAccess           = (BoundIndexerAccess)rewrittenLeft;
                BoundExpression?   rewrittenReceiver       = indexerAccess.ReceiverOpt;
                ImmutableArray <BoundExpression> arguments = indexerAccess.Arguments;
                PropertySymbol indexer = indexerAccess.Indexer;
                Debug.Assert(indexer.IsIndexer || indexer.IsIndexedProperty);
                return(MakePropertyAssignment(
                           syntax,
                           rewrittenReceiver,
                           indexer,
                           arguments,
                           indexerAccess.ArgumentRefKindsOpt,
                           indexerAccess.Expanded,
                           indexerAccess.ArgsToParamsOpt,
                           rewrittenRight,
                           type,
                           used));
            }

            case BoundKind.Local:
            case BoundKind.Parameter:
            case BoundKind.FieldAccess:
            {
                Debug.Assert(!isRef || rewrittenLeft.GetRefKind() != RefKind.None);
                return(new BoundAssignmentOperator(
                           syntax,
                           rewrittenLeft,
                           rewrittenRight,
                           isRef,
                           type));
            }

            case BoundKind.DiscardExpression:
            {
                return(rewrittenRight);
            }

            case BoundKind.Sequence:
                // An Index or Range pattern-based indexer, or an interpolated string handler conversion
                // that uses an indexer argument, produces a sequence with a nested
                // BoundIndexerAccess. We need to lower the final expression and produce an
                // update sequence
                var sequence = (BoundSequence)rewrittenLeft;
                if (sequence.Value.Kind == BoundKind.IndexerAccess)
                {
                    return(sequence.Update(
                               sequence.Locals,
                               sequence.SideEffects,
                               MakeStaticAssignmentOperator(
                                   syntax,
                                   sequence.Value,
                                   rewrittenRight,
                                   isRef,
                                   type,
                                   used),
                               type));
                }
                goto default;

            default:
            {
                Debug.Assert(!isRef);
                return(new BoundAssignmentOperator(
                           syntax,
                           rewrittenLeft,
                           rewrittenRight,
                           type));
            }
            }
        }
        /// <summary>
        /// Generates a lowered form of the assignment operator for the given left and right sub-expressions.
        /// Left and right sub-expressions must be in lowered form.
        /// </summary>
        private BoundExpression MakeStaticAssignmentOperator(
            SyntaxNode syntax,
            BoundExpression rewrittenLeft,
            BoundExpression rewrittenRight,
            bool isRef,
            TypeSymbol type,
            bool used)
        {
            switch (rewrittenLeft.Kind)
            {
            case BoundKind.DynamicIndexerAccess:
            case BoundKind.DynamicMemberAccess:
                throw ExceptionUtilities.UnexpectedValue(rewrittenLeft.Kind);

            case BoundKind.PropertyAccess:
            {
                Debug.Assert(!isRef);
                BoundPropertyAccess propertyAccess    = (BoundPropertyAccess)rewrittenLeft;
                BoundExpression     rewrittenReceiver = propertyAccess.ReceiverOpt;
                PropertySymbol      property          = propertyAccess.PropertySymbol;
                Debug.Assert(!property.IsIndexer);
                return(MakePropertyAssignment(
                           syntax,
                           rewrittenReceiver,
                           property,
                           ImmutableArray <BoundExpression> .Empty,
                           default(ImmutableArray <RefKind>),
                           false,
                           default(ImmutableArray <int>),
                           rewrittenRight,
                           type,
                           used));
            }

            case BoundKind.IndexerAccess:
            {
                Debug.Assert(!isRef);
                BoundIndexerAccess indexerAccess     = (BoundIndexerAccess)rewrittenLeft;
                BoundExpression    rewrittenReceiver = indexerAccess.ReceiverOpt;
                ImmutableArray <BoundExpression> rewrittenArguments = indexerAccess.Arguments;
                PropertySymbol indexer = indexerAccess.Indexer;
                Debug.Assert(indexer.IsIndexer || indexer.IsIndexedProperty);
                return(MakePropertyAssignment(
                           syntax,
                           rewrittenReceiver,
                           indexer,
                           rewrittenArguments,
                           indexerAccess.ArgumentRefKindsOpt,
                           indexerAccess.Expanded,
                           indexerAccess.ArgsToParamsOpt,
                           rewrittenRight,
                           type,
                           used));
            }

            case BoundKind.Local:
            {
                Debug.Assert(!isRef || ((BoundLocal)rewrittenLeft).LocalSymbol.RefKind != RefKind.None);
                return(new BoundAssignmentOperator(
                           syntax,
                           rewrittenLeft,
                           rewrittenRight,
                           type,
                           isRef: isRef));
            }

            case BoundKind.Parameter:
            {
                Debug.Assert(!isRef || rewrittenLeft.GetRefKind() != RefKind.None);
                return(new BoundAssignmentOperator(
                           syntax,
                           rewrittenLeft,
                           rewrittenRight,
                           isRef,
                           type));
            }

            case BoundKind.DiscardExpression:
            {
                return(rewrittenRight);
            }

            default:
            {
                Debug.Assert(!isRef);
                return(new BoundAssignmentOperator(
                           syntax,
                           rewrittenLeft,
                           rewrittenRight,
                           type));
            }
            }
        }