Repository: dotnet/roslyn
File: src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs (C#)

Code before:
                }
                else
                {
                    disposeMethod = enumeratorInfoOpt.IsAsync
                    ? (MethodSymbol)Compilation.GetWellKnownTypeMember(WellKnownMember.System_IAsyncDisposable__DisposeAsync)
                    : (MethodSymbol)Compilation.GetSpecialTypeMember(SpecialMember.System_IDisposable__Dispose);
                }
            }

            return new ForEachStatementInfo(
                enumeratorInfoOpt.IsAsync,
                enumeratorInfoOpt.GetEnumeratorInfo.Method.GetPublicSymbol(),
                enumeratorInfoOpt.MoveNextInfo.Method.GetPublicSymbol(),
                moveNextAwaitableInfo,
                currentProperty: ((PropertySymbol)enumeratorInfoOpt.CurrentPropertyGetter?.AssociatedSymbol).GetPublicSymbol(),
                disposeMethod.GetPublicSymbol(),
                disposeAwaitableInfo,
                enumeratorInfoOpt.ElementTypeWithAnnotations.GetPublicSymbol(),
                BoundNode.GetConversion(boundForEach.ElementConversion, boundForEach.ElementPlaceholder),
                BoundNode.GetConversion(enumeratorInfoOpt.CurrentConversion, enumeratorInfoOpt.CurrentPlaceholder));
        }

        public override DeconstructionInfo GetDeconstructionInfo(AssignmentExpressionSyntax node)
        {
            var upperNode = GetUpperBoundNode(node);
            while (upperNode is BoundConversion conversion)
            {
                upperNode = conversion.Operand;
            }

            if (upperNode is not BoundDeconstructionAssignmentOperator boundDeconstruction)
            {
                return default;
            }

            var boundConversion = boundDeconstruction.Right;
            Debug.Assert(boundConversion != null);
            if (boundConversion is null)
            {
                return default;
            }

            return new DeconstructionInfo(boundConversion.Conversion);
        }

        public override DeconstructionInfo GetDeconstructionInfo(ForEachVariableStatementSyntax node)
        {
            var boundForEach = (BoundForEachStatement)GetUpperBoundNode(node);
            if (boundForEach is null)
            {
                return default;

Review comment (suggestion):
>while (upperNode is BoundConversion conversion) [](http://example.com/codeflow?start=12&length=47)

It is not obvious to me that this is the right thing to do. Could you provide more details about the tree shape that we are trying to accommodate with this change? #Closed

Code after:
                }
                else
                {
                    disposeMethod = enumeratorInfoOpt.IsAsync
                    ? (MethodSymbol)Compilation.GetWellKnownTypeMember(WellKnownMember.System_IAsyncDisposable__DisposeAsync)
                    : (MethodSymbol)Compilation.GetSpecialTypeMember(SpecialMember.System_IDisposable__Dispose);
                }
            }

            return new ForEachStatementInfo(
                enumeratorInfoOpt.IsAsync,
                enumeratorInfoOpt.GetEnumeratorInfo.Method.GetPublicSymbol(),
                enumeratorInfoOpt.MoveNextInfo.Method.GetPublicSymbol(),
                moveNextAwaitableInfo,
                currentProperty: ((PropertySymbol)enumeratorInfoOpt.CurrentPropertyGetter?.AssociatedSymbol).GetPublicSymbol(),
                disposeMethod.GetPublicSymbol(),
                disposeAwaitableInfo,
                enumeratorInfoOpt.ElementTypeWithAnnotations.GetPublicSymbol(),
                BoundNode.GetConversion(boundForEach.ElementConversion, boundForEach.ElementPlaceholder),
                BoundNode.GetConversion(enumeratorInfoOpt.CurrentConversion, enumeratorInfoOpt.CurrentPlaceholder));
        }

        public override DeconstructionInfo GetDeconstructionInfo(AssignmentExpressionSyntax node)
        {
            var lowerNode = GetLowerBoundNode(node);
            if (lowerNode is not BoundDeconstructionAssignmentOperator boundDeconstruction)
            {
                return default;
            }

            var boundConversion = boundDeconstruction.Right;
            Debug.Assert(boundConversion != null);
            if (boundConversion is null)
            {
                return default;
            }

            return new DeconstructionInfo(boundConversion.Conversion);
        }

        public override DeconstructionInfo GetDeconstructionInfo(ForEachVariableStatementSyntax node)
        {
            var boundForEach = (BoundForEachStatement)GetUpperBoundNode(node);
            if (boundForEach is null)
            {
                return default;
            }

            var boundDeconstruction = boundForEach.DeconstructionOpt;
            Debug.Assert(boundDeconstruction != null || boundForEach.HasAnyErrors);
            if (boundDeconstruction is null)