private BoundExpression RewriteDeconstruction(
            ArrayBuilder <Binder.DeconstructionVariable> lhsTargets,
            Conversion conversion,
            TypeSymbol leftType,
            BoundExpression right,
            bool isUsed)
        {
            if (right.Kind == BoundKind.ConditionalOperator)
            {
                var conditional = (BoundConditionalOperator)right;
                Debug.Assert(!conditional.IsRef);
                return(conditional.Update(
                           conditional.IsRef,
                           VisitExpression(conditional.Condition),
                           RewriteDeconstruction(lhsTargets, conversion, leftType, conditional.Consequence, isUsed: true),
                           RewriteDeconstruction(lhsTargets, conversion, leftType, conditional.Alternative, isUsed: true),
                           conditional.ConstantValue,
                           leftType));
            }

            var temps = ArrayBuilder <LocalSymbol> .GetInstance();

            var             effects     = DeconstructionSideEffects.GetInstance();
            BoundExpression returnValue = ApplyDeconstructionConversion(lhsTargets, right, conversion, temps, effects, isUsed, inInit: true);

            effects.Consolidate();

            if (!isUsed)
            {
                // When a deconstruction is not used, the last effect is used as return value
                Debug.Assert(returnValue is null);
                var last = effects.PopLast();
                if (last is null)
                {
                    temps.Free();
                    effects.Free();
                    // Deconstructions with no effects lower to nothing. For example, `(_, _) = (1, 2);`
                    return(null);
                }

                return(_factory.Sequence(temps.ToImmutableAndFree(), effects.ToImmutableAndFree(), last));
            }
            else
            {
                if (!returnValue.HasErrors)
                {
                    returnValue = VisitExpression(returnValue);
                }

                return(_factory.Sequence(temps.ToImmutableAndFree(), effects.ToImmutableAndFree(), returnValue));
            }
        }
Exemple #2
0
        /// <summary>
        /// The left represents a tree of L-values. The structure of right can be missing parts of the tree on the left.
        /// The conversion holds nested conversisons and deconstruction information, which matches the tree from the left,
        /// and it provides the information to fill in the missing parts of the tree from the right and convert it to
        /// the tree from the left.
        ///
        /// A bound sequence is returned which has different phases of side-effects:
        /// - the initialization phase includes side-effects from the left, followed by evaluations of the right
        /// - the deconstruction phase includes all the invocations of Deconstruct methods and tuple element accesses below a Deconstruct call
        /// - the conversion phase
        /// - the assignment phase
        /// </summary>
        private BoundExpression RewriteDeconstruction(BoundTupleExpression left, Conversion conversion, BoundExpression right)
        {
            var temps = ArrayBuilder <LocalSymbol> .GetInstance();

            var effects = DeconstructionSideEffects.GetInstance();
            ArrayBuilder <Binder.DeconstructionVariable> lhsTargets = GetAssignmentTargetsAndSideEffects(left, temps, effects.init);

            BoundExpression returnTuple = ApplyDeconstructionConversion(lhsTargets, right, conversion, temps, effects, inInit: true);

            if (!returnTuple.HasErrors)
            {
                returnTuple = VisitExpression(returnTuple);
            }
            BoundExpression result = _factory.Sequence(temps.ToImmutableAndFree(), effects.ToImmutableAndFree(), returnTuple);

            Binder.DeconstructionVariable.FreeDeconstructionVariables(lhsTargets);

            return(result);
        }
        /// <summary>
        /// The left represents a tree of L-values. The structure of right can be missing parts of the tree on the left.
        /// The conversion holds nested conversions and deconstruction information, which matches the tree from the left,
        /// and it provides the information to fill in the missing parts of the tree from the right and convert it to
        /// the tree from the left.
        ///
        /// A bound sequence is returned which has different phases of side-effects:
        /// - the initialization phase includes side-effects from the left, followed by evaluations of the right
        /// - the deconstruction phase includes all the invocations of Deconstruct methods and tuple element accesses below a Deconstruct call
        /// - the conversion phase
        /// - the assignment phase
        /// </summary>
        private BoundExpression RewriteDeconstruction(BoundTupleExpression left, Conversion conversion, BoundExpression right, bool isUsed)
        {
            var temps = ArrayBuilder <LocalSymbol> .GetInstance();

            var effects = DeconstructionSideEffects.GetInstance();
            ArrayBuilder <Binder.DeconstructionVariable> lhsTargets = GetAssignmentTargetsAndSideEffects(left, temps, effects.init);

            BoundExpression returnValue = ApplyDeconstructionConversion(lhsTargets, right, conversion, temps, effects, isUsed, inInit: true);

            effects.Consolidate();

            BoundExpression result;

            if (!isUsed)
            {
                // When a deconstruction is not used, the last effect is used as return value
                Debug.Assert(returnValue is null);
                var last = effects.PopLast();
                if (last is null)
                {
                    // Deconstructions with no effects lower to nothing. For example, `(_, _) = (1, 2);`
                    result = null;
                    temps.Free();
                    _ = effects.ToImmutableAndFree();
                }
                else
                {
                    result = _factory.Sequence(temps.ToImmutableAndFree(), effects.ToImmutableAndFree(), last);
                }
            }
            else
            {
                if (!returnValue.HasErrors)
                {
                    returnValue = VisitExpression(returnValue);
                }
                result = _factory.Sequence(temps.ToImmutableAndFree(), effects.ToImmutableAndFree(), returnValue);
            }

            Binder.DeconstructionVariable.FreeDeconstructionVariables(lhsTargets);
            return(result);
        }