text: //===--- RValue.h - Exploded RValue Representation --------------*- C++ -*-===//
  //
  // This source file is part of the Swift.org open source project
  //
  // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
  // Licensed under Apache License v2.0 with Runtime Library Exception
  //
  // See http://swift.org/LICENSE.txt for license information
  // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
  //
  //===----------------------------------------------------------------------===//
  //
  // A storage structure for holding a destructured rvalue with an optional
  // cleanup(s).
  // Ownership of the rvalue can be "forwarded" to disable the associated
  // cleanup(s).
  //
  //===----------------------------------------------------------------------===//
  
  #ifndef SWIFT_LOWERING_RVALUE_H
  #define SWIFT_LOWERING_RVALUE_H
  
  #include "ManagedValue.h"
  #include "SILGenFunction.h"
  #include "llvm/ADT/SmallVector.h"
  
  namespace swift {
  namespace Lowering {
    class Initialization;
  
  /// An "exploded" SIL rvalue, in which tuple values are recursively
  /// destructured. (In SILGen we don't try to explode structs, because doing so
  /// would require considering resilience, a job we want to delegate to IRGen).
  class RValue {
    std::vector<ManagedValue> values;
    CanType type;
    unsigned elementsToBeAdded;
    
    /// Flag value used to mark an rvalue as invalid, because it was
    /// consumed or it was default-initialized.
    enum : unsigned { Used = ~0U };
    
    // Don't copy.
    RValue(const RValue &) = delete;
    RValue &operator=(const RValue &) = delete;
    
    void makeUsed() {
      elementsToBeAdded = Used;
      values = {};
    }
    
    /// Private constructor used by copy().
    RValue(const RValue &copied, SILGenFunction &gen, SILLocation l);
    
  public:
    /// Creates an invalid RValue object, in a "used" state.
    RValue() : elementsToBeAdded(Used) {}
    
    RValue(RValue &&rv)
      : values(std::move(rv.values)),
        type(rv.type),
        elementsToBeAdded(rv.elementsToBeAdded)
    {
      assert((rv.isComplete() || rv.isUsed())
             && "moving rvalue that wasn't complete?!");
      rv.elementsToBeAdded = Used;
    }
    RValue &operator=(RValue &&rv) {
      assert(isUsed() && "reassigning an unused rvalue?!");
      
      assert((rv.isComplete() || rv.isUsed())
             && "moving rvalue that wasn't complete?!");
      values = std::move(rv.values);
      type = rv.type;
      elementsToBeAdded = rv.elementsToBeAdded;
      rv.elementsToBeAdded = Used;
      return *this;
    }
    
    /// Create an RValue from a single value. If the value is of tuple type, it
    /// will be exploded.
    ///
    /// \param expr - the expression which yielded this r-value; its type
    ///   will become the substituted formal type of this r-value
    RValue(SILGenFunction &gen, Expr *expr, ManagedValue v);
  
    /// Create an RValue from a single value. If the value is of tuple type, it
    /// will be exploded.
    RValue(SILGenFunction &gen, SILLocation l, CanType type, ManagedValue v);
  
    /// Construct an RValue from a pre-exploded set of
    /// ManagedValues. Used to implement the extractElement* methods.
    RValue(ArrayRef<ManagedValue> values, CanType type);
    
    /// Create an RValue to which values will be subsequently added using
    /// addElement(), with the level of tuple expansion in the input specified
    /// by the abstraction pattern. The RValue will not be complete until all
    /// the elements have been added.
    explicit RValue(AbstractionPattern pattern, CanType type);
    
    /// Create an RValue to which values will be subsequently added using
    /// addElement(). The RValue will not be complete until all the elements have
    /// been added.
    explicit RValue(CanType type);
    
    /// True if the rvalue has been completely initialized by adding all its
    /// elements.
    bool isComplete() const & { return elementsToBeAdded == 0; }
    
    /// True if this rvalue has been used.
    bool isUsed() const & { return elementsToBeAdded == Used; }
    explicit operator bool() const & { return !isUsed(); }
  
    /// True if this rvalue was emitted into context.
    bool isInContext() const & { return isUsed(); }
    
    /// True if this represents an lvalue.
    bool isLValue() const & {
      return isa<InOutType>(type);
    }
    
    /// Add an element to the rvalue. The rvalue must not yet be complete.
    void addElement(RValue &&element) &;
    
    /// Add a ManagedValue element to the rvalue, exploding tuples if necessary.
    /// The rvalue must not yet be complete.
    void addElement(SILGenFunction &gen, ManagedValue element,
                    CanType formalType, SILLocation l) &;
    
    /// Forward an rvalue into a single value, imploding tuples if necessary.
    SILValue forwardAsSingleValue(SILGenFunction &gen, SILLocation l) &&;
  
    /// Forward an rvalue into a single value, imploding tuples if necessary, and
    /// introducing a potential conversion from semantic type to storage type.
    SILValue forwardAsSingleStorageValue(SILGenFunction &gen,
                                         SILType storageType,
                                         SILLocation l) &&;
  
    /// Get the rvalue as a single value, imploding tuples if necessary.
    ManagedValue getAsSingleValue(SILGenFunction &gen, SILLocation l) &&;
    
    /// Get the rvalue as a single unmanaged value, imploding tuples if necessary.
    /// The values must not require any cleanups.
    SILValue getUnmanagedSingleValue(SILGenFunction &gen, SILLocation l) const &;
    
    /// Peek at the single scalar value backing this rvalue without consuming it.
    /// The rvalue must not be of a tuple type.
    SILValue peekScalarValue() const & {
      assert(!isa<TupleType>(type) && "peekScalarValue of a tuple rvalue");
      assert(values.size() == 1 && "exploded scalar value?!");
      return values[0].getValue();
    }
  
    /// Peek at the single ManagedValue backing this rvalue without consuming it
    /// and return true if the value is not at +1.
    bool peekIsPlusZeroRValueOrTrivial() const & {
      assert(!isa<TupleType>(type) && "peekScalarValue of a tuple rvalue");
      assert(values.size() == 1 && "exploded scalar value?!");
      return values[0].isPlusZeroRValueOrTrivial();
    }
  
    ManagedValue getScalarValue() && {
      assert(!isa<TupleType>(type) && "getScalarValue of a tuple rvalue");
      assert(values.size() == 1);
      auto value = values[0];
      makeUsed();
      return value;
    }
  
    /// Use this rvalue to initialize an Initialization.
    void forwardInto(SILGenFunction &gen, SILLocation loc, Initialization *I) &&;
  
    /// Copy this rvalue to initialize an Initialization without consuming the
    /// rvalue.
    void copyInto(SILGenFunction &gen, SILLocation loc, Initialization *I) const&;
  
    /// Assign this r-value into the destination.
    void assignInto(SILGenFunction &gen, SILLocation loc, SILValue destAddr) &&;
    
    /// Forward the exploded SILValues into a SmallVector.
    void forwardAll(SILGenFunction &gen,
                    SmallVectorImpl<SILValue> &values) &&;
  
    ManagedValue materialize(SILGenFunction &gen, SILLocation loc) &&;
    
    /// Take the ManagedValues from this RValue into a SmallVector.
    void getAll(SmallVectorImpl<ManagedValue> &values) &&;
    
    /// Store the unmanaged SILValues into a SmallVector. The values must not
    /// require any cleanups.
    void getAllUnmanaged(SmallVectorImpl<SILValue> &values) const &;
    
    /// Extract a single tuple element from the rvalue.
    RValue extractElement(unsigned element) &&;
    
    /// Extract the tuple elements from the rvalue.
    void extractElements(SmallVectorImpl<RValue> &elements) &&;
    
    CanType getType() const & { return type; }
  
    /// Rewrite the type of this r-value.
    void rewriteType(CanType newType) & {
      // We only allow a very modest set of changes to a type.
      assert(newType == type ||
             (isa<TupleType>(newType) &&
              cast<TupleType>(newType)->getNumElements() == 1 &&
              cast<TupleType>(newType).getElementType(0) == type));
      type = newType;
    }
    
    /// Emit an equivalent value with independent ownership.
    RValue copy(SILGenFunction &gen, SILLocation l) const & {
      return RValue(*this, gen, l);
    }
  
    bool isObviouslyEqual(const RValue &rhs) const {
      assert(isComplete() && rhs.isComplete() && "Comparing incomplete rvalues");
  
      // Compare the count of elements instead of the type.
      if (values.size() != rhs.values.size())
        return false;
  
      return std::equal(values.begin(), values.end(), rhs.values.begin(),
                    [](const ManagedValue &lhs, const ManagedValue &rhs) -> bool {
                      return lhs.getValue() == rhs.getValue() &&
                      lhs.getCleanup() == rhs.getCleanup();
                    });
    }
  };
  
  } // end namespace Lowering
  } // end namespace swift
  
  #endif
  