private static void AcquireClaim(
            Place assignToPlace,
            Operand operand,
            HashSet <Claim> claimsBeforeStatement,
            HashSet <Claim> claimsAfterStatement)
        {
            switch (operand)
            {
            case Place place:
                var coreVariable = place.CoreVariable();
                var claim        = claimsBeforeStatement.SingleOrDefault(t => t.Variable == coreVariable);
                // Copy types don't have claims right now
                if (claim != null && assignToPlace != null)     // copy types don't have claims right now
                {
                    var loan = new Loan(assignToPlace.CoreVariable(),
                                        operand,
                                        claim.ObjectId);
                    if (!claimsAfterStatement.Contains(loan))
                    {
                        claimsAfterStatement.Add(loan);
                    }
                }
                break;

            case Constant _:
                // no loans to acquire
                break;

            default:
                throw NonExhaustiveMatchException.For(operand);
            }
        }
        private void AcquireOwnershipIfMoved(
            Place assignToPlace,
            FixedList <LocalVariableDeclaration> variables,
            HashSet <Claim> claimsAfterStatement)
        {
            if (assignToPlace == null)
            {
                return;
            }
            var assignToVariable = variables[assignToPlace.CoreVariable()];

            if (assignToVariable.Type is ReferenceType referenceType &&
                referenceType.IsOwned)
            {
                // We have taken ownership of a new object, assign it a new id
                var objectId = NewObjectId();
                // Variable acquires title on any new objects
                var title = new Title(assignToPlace.CoreVariable(), objectId);
                claimsAfterStatement.Add(title);
            }
        }
        private void AcquireClaims(
            Place assignToPlace,
            Value value,
            HashSet <Claim> claimsBeforeStatement,
            HashSet <Claim> claimsAfterStatement,
            FixedList <LocalVariableDeclaration> variables)
        {
            switch (value)
            {
            case ConstructorCall constructorCall:
                foreach (var argument in constructorCall.Arguments)
                {
                    AcquireClaim(assignToPlace, argument, claimsBeforeStatement, claimsAfterStatement);
                }
                // We have made a new object, assign it a new id
                var objectId = NewObjectId();
                // Variable acquires title on any new objects
                var title = new Title(assignToPlace.CoreVariable(), objectId);
                claimsAfterStatement.Add(title);
                break;

            case UnaryOperation unaryOperation:
                AcquireClaim(assignToPlace, unaryOperation.Operand, claimsBeforeStatement, claimsAfterStatement);
                break;

            case BinaryOperation binaryOperation:
                AcquireClaim(assignToPlace, binaryOperation.LeftOperand, claimsBeforeStatement, claimsAfterStatement);
                AcquireClaim(assignToPlace, binaryOperation.RightOperand, claimsBeforeStatement, claimsAfterStatement);
                break;

            case IntegerConstant _:
                // no loans to acquire
                break;

            case Operand operand:
                AcquireClaim(assignToPlace, operand, claimsBeforeStatement, claimsAfterStatement);
                break;

            case FunctionCall functionCall:
                if (functionCall.Self != null)
                {
                    AcquireClaim(assignToPlace, functionCall.Self, claimsBeforeStatement,
                                 claimsAfterStatement);
                }
                foreach (var argument in functionCall.Arguments)
                {
                    AcquireClaim(assignToPlace, argument, claimsBeforeStatement,
                                 claimsAfterStatement);
                }
                AcquireOwnershipIfMoved(assignToPlace, variables, claimsAfterStatement);
                break;

            case VirtualFunctionCall virtualFunctionCall:
                if (virtualFunctionCall.Self != null)
                {
                    AcquireClaim(assignToPlace, virtualFunctionCall.Self, claimsBeforeStatement, claimsAfterStatement);
                }
                foreach (var argument in virtualFunctionCall.Arguments)
                {
                    AcquireClaim(assignToPlace, argument, claimsBeforeStatement, claimsAfterStatement);
                }
                AcquireOwnershipIfMoved(assignToPlace, variables, claimsAfterStatement);
                break;

            default:
                throw NonExhaustiveMatchException.For(value);
            }
        }