private static Instruction FindNextConstructionMethod(MethodDefinition method, Instruction instruction)
        {
            var cursor = instruction;
            //the description object should be on the stack, and nothing on top of it.
            int stackDepth = 1;

            while (cursor.Next != null)
            {
                cursor = cursor.Next;

                var result = CecilHelpers.MatchesDelegateProducingPattern(method, cursor, CecilHelpers.DelegateProducingPattern.MatchSide.Start);
                if (result != null)
                {
                    cursor      = result.Instructions.Last();
                    stackDepth += 1;
                    continue;
                }

                if (CecilHelpers.IsUnsupportedBranch(cursor))
                {
                    UserError.DC0010(method, cursor).Throw();
                }

                if (cursor.OpCode == OpCodes.Call && cursor.Operand is MethodReference mr && IsLambdaJobDescriptionConstructionMethod(mr))
                {
                    return(cursor);
                }

                stackDepth -= cursor.GetPopDelta();
                if (stackDepth < 1)
                {
                    UserError.DC0011(method, cursor).Throw();
                }

                stackDepth += cursor.GetPushDelta();
            }

            return(null);
        }
        public static Instruction FindInstructionThatPushedArg(MethodDefinition containingMethod, int argNumber,
                                                               Instruction callInstructionsWhoseArgumentsWeWantToFind)
        {
            containingMethod.Body.EnsurePreviousAndNextAreSet();

            var cursor = callInstructionsWhoseArgumentsWeWantToFind.Previous;

            int stackSlotWhoseWriteWeAreLookingFor     = argNumber;
            int stackSlotWhereNextPushWouldBeWrittenTo = InstructionExtensions.GetPopDelta(callInstructionsWhoseArgumentsWeWantToFind);

            var seenInstructions = new HashSet <Instruction>()
            {
                callInstructionsWhoseArgumentsWeWantToFind, cursor
            };

            while (cursor != null)
            {
                var pushAmount = cursor.GetPushDelta();
                var popAmount  = cursor.GetPopDelta();

                var result = CecilHelpers.MatchesDelegateProducingPattern(containingMethod, cursor, CecilHelpers.DelegateProducingPattern.MatchSide.End);
                if (result != null)
                {
                    //so we are crawling backwards through isntructions.  if we find a "this is roslyn caching a delegate" sequence,
                    //we're going to pretend it is a single instruction, that pushes the delegate on the stack, and pops nothing.
                    cursor     = result.Instructions.First();
                    pushAmount = 1;
                    popAmount  = 0;
                }
                else if (cursor.IsBranch())
                {
                    var target = (Instruction)cursor.Operand;
                    if (!seenInstructions.Contains(target))
                    {
                        if (IsUnsupportedBranch(cursor))
                        {
                            UserError.DC0010(containingMethod, cursor).Throw();
                        }
                    }
                }


                for (int i = 0; i != pushAmount; i++)
                {
                    stackSlotWhereNextPushWouldBeWrittenTo--;
                    if (stackSlotWhereNextPushWouldBeWrittenTo == stackSlotWhoseWriteWeAreLookingFor)
                    {
                        return(cursor);
                    }
                }

                for (int i = 0; i != popAmount; i++)
                {
                    stackSlotWhereNextPushWouldBeWrittenTo++;
                }

                cursor = cursor.Previous;
                seenInstructions.Add(cursor);
            }

            return(null);
        }