private void Analyze(IStatement statement, ReachabilityGraph graph, VariableScope scope)
        {
            switch (statement)
            {
            default:
                throw ExhaustiveMatch.Failed(statement);

            case IVariableDeclarationStatement stmt:
            {
                var initializer = AnalyzeAssignmentSource(stmt.Initializer, graph, scope);
                var variable    = VariableDeclared(stmt, graph, scope);
                // TODO this variable's references effectively go away when it is no longer live
                // TODO how does the idea of in use variables work with variables?
                graph.Assign(variable, initializer);
                if (!stmt.VariableIsLiveAfter.Result)
                {
                    // Variable is dead, effectively it can be removed
                    variable?.Dead();
                }
            }
            break;

            case IExpressionStatement stmt:
                Analyze(stmt.Expression, graph, scope);
                break;

            case IResultStatement exp:
                // TODO deal with passing the result to the block
                Analyze(exp.Expression, graph, scope);
                break;
            }
        }
        /// <summary>
        /// Analyze an expression to apply its effects to the reachability graph.
        /// </summary>
        /// <returns>The place of the object resulting from evaluating this expression or null
        /// if the there is no result or the result is not an object reference.</returns>
        private TempValue?Analyze(IExpression?expression, ReachabilityGraph graph, VariableScope scope)
        {
            if (expression is null)
            {
                return(null);
            }
            var referenceType   = expression.DataType.Known().UnderlyingReferenceType();
            var isReferenceType = !(referenceType is null);

            switch (expression)
            {
            default:
                throw ExhaustiveMatch.Failed(expression);

            case IAssignmentExpression exp:
            {
                var leftPlace  = AnalyzeAssignmentPlace(exp.LeftOperand, graph, scope);
                var rightPlace = AnalyzeAssignmentSource(exp.RightOperand, graph, scope);
                graph.Assign(leftPlace, rightPlace);
                return(null);
            }

            case ISelfExpression exp:
                throw new InvalidOperationException($"`self` reference not wrapped in move, borrow, or share");

            case IMoveExpression exp:
            {
                _ = referenceType ?? throw new InvalidOperationException("Can't move value type");

                // The referent should be a name or `self` so we don't need to evaluate it
                var variable = graph.GetVariableFor(exp.ReferencedSymbol);
                var temp     = graph.AddTempValue(exp);
                temp?.MoveFrom(variable);
                return(temp);
            }

            case IBorrowExpression exp:
            {
                _ = referenceType ?? throw new InvalidOperationException("Can't borrow value type");

                // If there is a variable, it is a simple borrow expression
                var variable = graph.TryGetVariableFor(exp.ReferencedSymbol);
                if (!(variable is null))
                {
                    var temp = graph.AddTempValue(exp);
                    temp?.BorrowFrom(variable);
                    return(temp);
                }

                // Can this happen?
                throw new NotImplementedException();
                //var temp = Analyze(exp.)
                //var temp = graph.NewTempValue(referenceType);
                //temp.BorrowFrom(variable);
                //return temp;
            }

            case IShareExpression exp:
            {
                _ = referenceType ?? throw new InvalidOperationException("Can't share value type");

                // The referent should be a name or `self` so we don't need to evaluate it
                var variable = graph.TryGetVariableFor(exp.ReferencedSymbol);
                if (!(variable is null))
                {
                    var temp = graph.AddTempValue(exp);
                    temp?.ShareFrom(variable);
                    return(temp);
                }