You are a helpful assistant generating synthetic data that captures *System 1* and *System 2* thinking, *creativity*, and *metacognitive reflection*. Follow these steps in sequence, using tags [sys1] and [end sys1] for *System 1* sections and [sys2] and [end sys2] for *System 2* sections.

1. *Identify System 1 and System 2 Thinking Requirements:*
   - Carefully read the text.
   - Identify parts of the text that require quick, straightforward responses (*System 1*). Mark these sections with [sys1] and [end sys1].
   - Identify parts that require in-depth, reflective thinking (*System 2*), marked with [sys2] and [end sys2].

2. *Apply Step-by-Step Problem Solving with Creativity and Metacognitive Reflection for System 2 Sections:*

   *2.1 Understand the Problem:*
   - Objective: Fully comprehend the issue, constraints, and relevant context.
   - Reflection: "What do I understand about this issue? What might I be overlooking?"
   - Creative Perspective: Seek hidden patterns or possibilities that could reveal deeper insights or innovative connections.

   *2.2 Analyze the Information:*
   - Objective: Break down the problem logically.
   - Reflection: "Am I considering all factors? Are there any assumptions that need challenging?"
   - Creative Perspective: Explore unique patterns or overlooked relationships in the data that could add depth to the analysis.

   *2.3 Generate Hypotheses:*
   - Objective: Propose at least 10 hypotheses, each with a Confidence Score (0.0 to 1.0) and Creative Score (0.0 to 1.0), reflecting originality, surprise, and utility.
   - Reflection: "Have I explored all possible explanations or approaches, both conventional and unconventional?"
   - Creative Perspective: Consider novel angles that might provide unexpected insights.

   *2.4 Anticipate Future Steps and Obstacles:*
   - Objective: Make predictions, accounting for potential outcomes and obstacles.
   - Reflection: "What challenges might I face? Is my plan flexible for different scenarios?"
   - Creative Perspective: Visualize unforeseen outcomes and adapt plans to make use of them effectively.

   *2.5 Evaluate Hypotheses:*
   - Objective: Assess hypotheses based on feasibility, risk, and potential impact.
   - Evaluation: Refine Confidence and Creative Scores as needed.
   - Reflection: "Am I unbiased in my assessment? Which options fit best with the overall objectives?"
   - Creative Perspective: Identify hidden opportunities or overlooked details in each hypothesis.

   *2.6 Select the Best Hypothesis:*
   - Objective: Choose the most promising, strategic hypothesis.
   - Reflection: "Why does this hypothesis stand out? How does it uniquely address the issue?"
   - Creative Perspective: Consider any underutilized potential in the selected approach.

   *2.7 Implement the Hypothesis:*
   - Objective: Outline actionable steps for testing the hypothesis.
   - Reflection: "Is this plan practical? What resources or preparation are required?"
   - Creative Perspective: Refine steps to maximize effectiveness and yield unexpected benefits.

   *2.8 Monitor and Review Progress:*
   - Objective: Review progress, noting areas for improvement.
   - Reflection: "What’s working well? What could be improved?"
   - Creative Perspective: Look for emerging patterns that could refine future approaches.

   *2.9 Reflect and Capture Insights:*
   - Objective: Summarize lessons learned and insights gained for future reference.
   - Reflection: "What new understanding has emerged from this process?"
   - Creative Perspective: Identify innovative insights or patterns that could be applied to similar challenges.

3. *Generate Text Output with Interleaved System 1 and System 2 Responses:*
   - Use the tags [sys1] and [sys2] throughout.
   - Aim for a lengthier, detailed response. Combine both direct, straightforward *System 1* insights and reflective, deeply analytical *System 2* segments to capture a blend of quick observations and thoughtful analysis.

---

### *Example Input Text:*

You are tasked with analyzing a sudden shift in customer preferences in a tech market. There has been a noticeable decline in demand for physical devices, with customers increasingly interested in digital-only options. The challenge is to understand this shift, generate hypotheses for why it might be occurring, and explore potential strategies for adapting to this new trend.

---

### *Processed Output with System 1 and System 2 Thinking:*

The tech market is experiencing a shift in customer demand, moving away from physical devices toward digital-only options.

[sys1]
Customer demand has shifted from physical devices to digital-only options.
We need to understand why this change is happening and find strategies to address it.
Key factors may include cost, convenience, and technological trends.
[end sys1]

[sys2]
**2.1 Understand the Problem:**
The goal is to understand the underlying reasons for the shift in demand from physical devices to digital-only options, then develop a strategy to adapt.

*Reflection:* 
"I understand that preferences are changing, but what might be driving this? Is it primarily cost, or are there other factors such as convenience or sustainability?"

*Creative Perspective:* 
"Could there be a larger trend in digital minimalism or a preference for eco-friendly solutions that we’re missing? What unseen motivations might explain this shift?"

**2.2 Analyze the Information:**
There are multiple possible factors driving this shift, from economic influences to cultural shifts. It’s essential to isolate each factor and understand its impact.

*Reflection:* 
"Am I fully considering the various economic and social influences? Could there be a technological factor, like better internet speeds, that makes digital-only products more accessible?"

*Creative Perspective:* 
"Are there patterns or trends in other markets that could shed light on this shift? Could this be part of a larger trend toward virtual experiences?"

**2.3 Generate Hypotheses:**
1. Customers prefer digital options due to lower costs. (Confidence: 0.8, Creative: 0.4)
2. There’s a growing trend toward minimalism and reduced physical clutter. (Confidence: 0.7, Creative: 0.7)
3. Digital products offer greater flexibility and ease of use. (Confidence: 0.6, Creative: 0.6)
4. Environmental concerns are pushing consumers away from physical goods. (Confidence: 0.6, Creative: 0.8)
5. Advances in tech make digital-only options more functional. (Confidence: 0.8, Creative: 0.5)
6. Pandemic-era remote work increased demand for digital solutions. (Confidence: 0.7, Creative: 0.6)
7. Media coverage of the environmental impact of physical devices affects preferences. (Confidence: 0.5, Creative: 0.7)
8. There’s an increase in global digital literacy, expanding market access. (Confidence: 0.6, Creative: 0.6)
9. Customers view digital as more convenient and scalable for future needs. (Confidence: 0.7, Creative: 0.5)
10. Younger consumers prefer the aesthetics and convenience of digital products. (Confidence: 0.6, Creative: 0.6)

*Reflection:* 
"Have I considered all possible influences? Are there any surprising factors that could explain this shift?"

*Creative Perspective:* 
"Could specific social trends, like the rise of influencer culture or digital-first lifestyles, be influencing customer choices?"

**2.4 Anticipate Future Steps and Obstacles:**
*Objective:* Anticipate possible challenges, such as resistance from segments still preferring physical products.

*Reflection:* 
"What market obstacles might we face if we shift our focus to digital-only? Are there sub-segments that still prioritize physical products?"

*Creative Perspective:* 
"Could expanding digital options help us reach a more global audience? Are there emerging trends that we could leverage in our strategy?"

[end sys2]

[sys1]
To address this shift, consider a strategy that incorporates both digital-only offerings and educational campaigns about the benefits of digital solutions.
Use insights from customer feedback and current trends to guide product development.
Focus on flexibility and adaptation to cater to different customer segments.
[end sys1]


//===--- SILConstants.h - SIL constant representation -----------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This defines an interface to represent SIL level structured constants in a
// memory efficient way.
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_SIL_CONSTANTS_H
#define SWIFT_SIL_CONSTANTS_H

#include "swift/AST/SubstitutionMap.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILValue.h"
#include "llvm/Support/CommandLine.h"

namespace swift {
class SingleValueInstruction;
class SILValue;
class SILBuilder;
class SerializedSILLoader;

struct AggregateSymbolicValue;
struct SymbolicArrayStorage;
struct DerivedAddressValue;
struct EnumWithPayloadSymbolicValue;
struct SymbolicValueMemoryObject;
struct UnknownSymbolicValue;
struct SymbolicClosure;

extern llvm::cl::opt<unsigned> ConstExprLimit;

/// An abstract class that exposes functions for allocating symbolic values.
/// The implementors of this class have to determine where to allocate them and
/// and manage the lifetime of the allocated symbolic values.
class SymbolicValueAllocator {
public:
  virtual ~SymbolicValueAllocator() {}

  /// Allocate raw bytes.
  /// \param byteSize number of bytes to allocate.
  /// \param alignment alignment for the allocated bytes.
  virtual void *allocate(unsigned long byteSize, unsigned alignment) = 0;

  /// Allocate storage for a given number of elements of a specific type
  /// provided as a template parameter. Precondition: \c T must have an
  /// accesible zero argument constructor.
  /// \param numElts number of elements of the type to allocate.
  template <typename T> T *allocate(unsigned numElts) {
    T *res = (T *)allocate(sizeof(T) * numElts, alignof(T));
    for (unsigned i = 0; i != numElts; ++i)
      new (res + i) T();
    return res;
  }
};

/// A class that allocates symbolic values in a local bump allocator. The
/// lifetime of the bump allocator is same as the lifetime of \c this object.
class SymbolicValueBumpAllocator : public SymbolicValueAllocator {
private:
  llvm::BumpPtrAllocator bumpAllocator;

public:
  SymbolicValueBumpAllocator() {}
  ~SymbolicValueBumpAllocator() {}

  void *allocate(unsigned long byteSize, unsigned alignment) override {
    return bumpAllocator.Allocate(byteSize, alignment);
  }
};

/// When we fail to constant fold a value, this captures a reason why,
/// allowing the caller to produce a specific diagnostic.  The "Unknown"
/// SymbolicValue representation also includes a pointer to the SILNode in
/// question that was problematic.
class UnknownReason {
public:
  enum UnknownKind {
    // TODO: Eliminate the default kind, by making classifications for each
    // failure mode.
    Default,

    /// The constant expression was too big.  This is reported on a random
    /// instruction within the constexpr that triggered the issue.
    TooManyInstructions,

    /// A control flow loop was found.
    Loop,

    /// Integer overflow detected.
    Overflow,

    /// Trap detected. Traps will a message as a payload.
    Trap,

    /// An operation was applied over operands whose symbolic values were
    /// constants but were not valid for the operation.
    InvalidOperandValue,

    /// Encountered an instruction not supported by the interpreter.
    UnsupportedInstruction,

    /// Encountered a function call whose arguments are not constants.
    CallArgumentUnknown,

    /// Encountered a function call where the body of the called function is
    /// not available.
    CalleeImplementationUnknown,

    /// Attempted to load from/store into a SIL value that was not tracked by
    /// the interpreter.
    UntrackedSILValue,

    /// Encountered a checked cast operation whose result cannot be evaluated
    /// to a constant.
    UnknownCastResult,

    /// Attempted to find a concrete protocol conformance for a witness method
    /// and failed.
    UnknownWitnessMethodConformance,

    /// Attempted to determine the SIL function of a witness method  and failed.
    NoWitnesTableEntry,

    /// The value of a top-level variable cannot be determined to be a constant.
    /// This is only relevant in the backward evaluation mode, which is used by
    /// #assert.
    NotTopLevelConstant,

    /// A top-level value has multiple writers. This is only relevant in the
    /// non-flow-sensitive evaluation mode,  which is used by #assert.
    MutipleTopLevelWriters,

    /// Indicates the return value of an instruction that was not evaluated
    /// during interpretation.
    ReturnedByUnevaluatedInstruction,

    /// Indicates that the value was possibly modified by an instruction
    /// that was not evaluated during the interpretation.
    MutatedByUnevaluatedInstruction,
  };

private:
  UnknownKind kind;

  // Auxiliary information for different unknown kinds.
  union {
    SILFunction *function;   // For CalleeImplementationUnknown
    const char *trapMessage; // For Trap.
    unsigned argumentIndex;  // For CallArgumentUnknown
  } payload;

public:
  UnknownKind getKind() { return kind; }

  static bool isUnknownKindWithPayload(UnknownKind kind) {
    switch (kind) {
    case UnknownKind::CalleeImplementationUnknown:
    case UnknownKind::Trap:
    case UnknownKind::CallArgumentUnknown:
      return true;
    default:
      return false;
    }
  }

  static UnknownReason create(UnknownKind kind) {
    assert(!isUnknownKindWithPayload(kind));
    UnknownReason reason;
    reason.kind = kind;
    return reason;
  }

  static UnknownReason createCalleeImplementationUnknown(SILFunction *callee) {
    assert(callee);
    UnknownReason reason;
    reason.kind = UnknownKind::CalleeImplementationUnknown;
    reason.payload.function = callee;
    return reason;
  }

  SILFunction *getCalleeWithoutImplmentation() {
    assert(kind == UnknownKind::CalleeImplementationUnknown);
    return payload.function;
  }

  static UnknownReason createTrap(StringRef message,
                                  SymbolicValueAllocator &allocator) {
    // Copy and null terminate the string.
    size_t size = message.size();
    char *messagePtr = allocator.allocate<char>(size + 1);
    std::uninitialized_copy(message.begin(), message.end(), messagePtr);
    messagePtr[size] = '\0';

    UnknownReason reason;
    reason.kind = UnknownKind::Trap;
    reason.payload.trapMessage = messagePtr;
    return reason;
  }

  const char *getTrapMessage() {
    assert(kind == UnknownKind::Trap);
    return payload.trapMessage;
  }

  static UnknownReason createCallArgumentUnknown(unsigned argIndex) {
    UnknownReason reason;
    reason.kind = UnknownKind::CallArgumentUnknown;
    reason.payload.argumentIndex = argIndex;
    return reason;
  }

  unsigned getArgumentIndex() {
    assert(kind == UnknownKind::CallArgumentUnknown);
    return payload.argumentIndex;
  }
};

/// This is the symbolic value tracked for each SILValue in a scope.  We
/// support multiple representational forms for the constant node in order to
/// avoid pointless memory bloat + copying.  This is intended to be a
/// light-weight POD type we can put in hash tables and pass around by-value.
///
/// Internally, this value has multiple ways to represent the same sorts of
/// symbolic values (e.g. to save memory).  It provides a simpler public
/// interface though.
class SymbolicValue {
private:
  enum RepresentationKind {
    /// This value is an alloc stack that has not (yet) been initialized
    /// by flow-sensitive analysis.
    RK_UninitMemory,

    /// This symbolic value cannot be determined, carries multiple values
    /// (i.e., varies dynamically at the top level), or is of some type that
    /// we cannot analyze and propagate (e.g. NSObject).
    ///
    RK_Unknown,

    /// This value is known to be a metatype reference.  The type is stored
    /// in the "metatype" member.
    RK_Metatype,

    /// This value is known to be a function reference, e.g. through
    /// function_ref directly, or a devirtualized method reference.
    RK_Function,

    /// This value is represented with a bump-pointer allocated APInt.
    RK_Integer,

    /// This value is represented with an inline integer representation.
    RK_IntegerInline,

    /// This value is represented with a bump-pointer allocated char array
    /// representing a UTF-8 encoded string.
    RK_String,

    /// This value is a struct or tuple of constants.  This is tracked by the
    /// "aggregate" member of the value union.
    RK_Aggregate,

    /// This value is an enum with no payload.
    RK_Enum,

    /// This value is an enum with a payload.
    RK_EnumWithPayload,

    /// This represents the address of a memory object.
    RK_DirectAddress,

    /// This represents an index *into* a memory object.
    RK_DerivedAddress,

    /// This represents the internal storage of an array.
    RK_ArrayStorage,

    /// This represents an array.
    RK_Array,

    /// This represents a closure.
    RK_Closure,
  };

  union {
    /// When the value is Unknown, this contains information about the
    /// unfoldable part of the computation.
    UnknownSymbolicValue *unknown;

    /// This is always a SILType with an object category.  This is the value
    /// of the underlying instance type, not the MetatypeType.
    TypeBase *metatype;

    SILFunction *function;

    /// When this SymbolicValue is of "Integer" kind, this pointer stores
    /// the words of the APInt value it holds.
    uint64_t *integer;

    /// This holds the bits of an integer for an inline representation.
    uint64_t integerInline;

    /// When this SymbolicValue is of "String" kind, this pointer stores
    /// information about the StringRef value it holds.
    const char *string;

    /// When this SymbolicValue is of "Aggregate" kind, this pointer stores
    /// information about the aggregate elements, its type and count.
    const AggregateSymbolicValue *aggregate;

    /// When this SymbolicValue is of "Enum" kind, this pointer stores
    /// information about the enum case type.
    EnumElementDecl *enumVal;

    /// When this SymbolicValue is of "EnumWithPayload" kind, this pointer
    /// stores information about the enum case type and its payload.
    EnumWithPayloadSymbolicValue *enumValWithPayload;

    /// When the representationKind is "DirectAddress", this pointer is the
    /// memory object referenced.
    SymbolicValueMemoryObject *directAddress;

    /// When this SymbolicValue is of "DerivedAddress" kind, this pointer stores
    /// information about the memory object and access path of the access.
    DerivedAddressValue *derivedAddress;

    // The following two fields are for representing an Array.
    //
    // In Swift, an array is a non-trivial struct that stores a reference to an
    // internal storage: _ContiguousArrayStorage. Though arrays have value
    // semantics in Swift, it is not the case in SIL. In SIL, an array can be
    // mutated by taking the address of the internal storage i.e., through a
    // shared, mutable pointer to the internal storage of the array. In fact,
    // this is how an array initialization is lowered in SIL. Therefore, the
    // symbolic representation of an array is an addressable "memory cell"
    // (i.e., a SymbolicValueMemoryObject) containing the array storage. The
    // array storage is modeled by the type: SymbolicArrayStorage. This
    // representation of the array enables obtaining the address of the internal
    // storage and modifying the array through that address. Array operations
    // such as `append` that mutate an array must clone the internal storage of
    // the array, following the semantics of the Swift implementation of those
    // operations.

    /// Representation of array storage (RK_ArrayStorage). SymbolicArrayStorage
    /// is a container for a sequence of symbolic values.
    SymbolicArrayStorage *arrayStorage;

    /// When this symbolic value is of an "Array" kind, this stores a memory
    /// object that contains a SymbolicArrayStorage value.
    SymbolicValueMemoryObject *array;

    /// When this symbolic value is of "Closure" kind, store a pointer to the
    /// symbolic representation of the closure.
    SymbolicClosure *closure;
  } value;

  RepresentationKind representationKind : 8;

  union {
    /// This is the number of bits in an RK_Integer or RK_IntegerInline
    /// representation, which makes the number of entries in the list derivable.
    unsigned integerBitwidth;

    /// This is the number of bytes for an RK_String representation.
    unsigned stringNumBytes;
  } auxInfo;

public:
  /// This enum is used to indicate the sort of value held by a SymbolicValue
  /// independent of its concrete representation.  This is the public
  /// interface to SymbolicValue.
  enum Kind {
    /// This is a value that isn't a constant.
    Unknown,

    /// This is a known metatype value.
    Metatype,

    /// This is a function, represented as a SILFunction.
    Function,

    /// This is an integer constant.
    Integer,

    /// String values may have SIL type of Builtin.RawPointer or Builtin.Word
    /// type.
    String,

    /// This can be an array, struct, tuple, etc.
    Aggregate,

    /// This is an enum without payload.
    Enum,

    /// This is an enum with payload (formally known as "associated value").
    EnumWithPayload,

    /// This value represents the address of, or into, a memory object.
    Address,

    /// This represents an internal array storage.
    ArrayStorage,

    /// This represents an array value.
    Array,

    /// This represents a closure.
    Closure,

    /// These values are generally only seen internally to the system, external
    /// clients shouldn't have to deal with them.
    UninitMemory
  };

  /// For constant values, return the type classification of this value.
  Kind getKind() const;

  /// Return true if this represents a constant value.
  bool isConstant() const {
    auto kind = getKind();
    return kind != Unknown && kind != UninitMemory;
  }

  static SymbolicValue getUnknown(SILNode *node, UnknownReason reason,
                                  llvm::ArrayRef<SourceLoc> callStack,
                                  SymbolicValueAllocator &allocator);

  /// Return true if this represents an unknown result.
  bool isUnknown() const { return getKind() == Unknown; }

  /// Return the call stack for an unknown result.
  ArrayRef<SourceLoc> getUnknownCallStack() const;

  /// Return the node that triggered an unknown result.
  SILNode *getUnknownNode() const;

  /// Return the reason an unknown result was generated.
  UnknownReason getUnknownReason() const;

  static SymbolicValue getUninitMemory() {
    SymbolicValue result;
    result.representationKind = RK_UninitMemory;
    return result;
  }

  static SymbolicValue getMetatype(CanType type) {
    SymbolicValue result;
    result.representationKind = RK_Metatype;
    result.value.metatype = type.getPointer();
    return result;
  }

  CanType getMetatypeValue() const {
    assert(representationKind == RK_Metatype);
    return CanType(value.metatype);
  }

  static SymbolicValue getFunction(SILFunction *fn) {
    assert(fn && "Function cannot be null");
    SymbolicValue result;
    result.representationKind = RK_Function;
    result.value.function = fn;
    return result;
  }

  SILFunction *getFunctionValue() const {
    assert(getKind() == Function);
    return value.function;
  }

  static SymbolicValue getInteger(int64_t value, unsigned bitWidth);
  static SymbolicValue getInteger(const APInt &value,
                                  SymbolicValueAllocator &allocator);

  APInt getIntegerValue() const;
  unsigned getIntegerValueBitWidth() const;

  /// Returns a SymbolicValue representing a UTF-8 encoded string.
  static SymbolicValue getString(StringRef string,
                                 SymbolicValueAllocator &allocator);

  /// Returns the UTF-8 encoded string underlying a SymbolicValue.
  StringRef getStringValue() const;

  /// This returns an aggregate value with the specified elements in it.  This
  /// copies the member values into the specified Allocator.
  static SymbolicValue getAggregate(ArrayRef<SymbolicValue> members,
                                    Type aggregateType,
                                    SymbolicValueAllocator &allocator);

  ArrayRef<SymbolicValue> getAggregateMembers() const;

  /// Return the type of this aggregate symbolic value.
  Type getAggregateType() const;

  /// This returns a constant Symbolic value for the enum case in `decl`, which
  /// must not have an associated value.
  static SymbolicValue getEnum(EnumElementDecl *decl) {
    assert(decl);
    SymbolicValue result;
    result.representationKind = RK_Enum;
    result.value.enumVal = decl;
    return result;
  }

  /// `payload` must be a constant.
  static SymbolicValue getEnumWithPayload(EnumElementDecl *decl,
                                          SymbolicValue payload,
                                          SymbolicValueAllocator &allocator);

  EnumElementDecl *getEnumValue() const;

  SymbolicValue getEnumPayloadValue() const;

  /// Return a symbolic value that represents the address of a memory object.
  static SymbolicValue getAddress(SymbolicValueMemoryObject *memoryObject) {
    SymbolicValue result;
    result.representationKind = RK_DirectAddress;
    result.value.directAddress = memoryObject;
    return result;
  }

  /// Return a symbolic value that represents the address of a memory object
  /// indexed by a path.
  static SymbolicValue getAddress(SymbolicValueMemoryObject *memoryObject,
                                  ArrayRef<unsigned> indices,
                                  SymbolicValueAllocator &allocator);

  /// Return the memory object of this reference along with any access path
  /// indices involved.
  SymbolicValueMemoryObject *
  getAddressValue(SmallVectorImpl<unsigned> &accessPath) const;

  /// Return just the memory object for an address value.
  SymbolicValueMemoryObject *getAddressValueMemoryObject() const;

  /// Create a symbolic array storage containing \c elements.
  static SymbolicValue
  getSymbolicArrayStorage(ArrayRef<SymbolicValue> elements, CanType elementType,
                          SymbolicValueAllocator &allocator);

  /// Create a symbolic array using the given symbolic array storage, which
  /// contains the array elements.
  static SymbolicValue getArray(Type arrayType, SymbolicValue arrayStorage,
                                SymbolicValueAllocator &allocator);

  /// Return the elements stored in this SymbolicValue of "ArrayStorage" kind.
  ArrayRef<SymbolicValue> getStoredElements(CanType &elementType) const;

  /// Return the symbolic value representing the internal storage of this array.
  SymbolicValue getStorageOfArray() const;

  /// Return the symbolic value representing the address of the element of this
  /// array at the given \c index. The return value is a derived address whose
  /// base is the memory object \c value.array (which contains the array
  /// storage) and whose accesspath is \c index.
  SymbolicValue getAddressOfArrayElement(SymbolicValueAllocator &allocator,
                                         unsigned index) const;

  /// Return the type of this array symbolic value.
  Type getArrayType() const;

  /// Create and return a symbolic value that represents a closure.
  /// \param target SILFunction corresponding the target of the closure.
  /// \param capturedArguments an array consisting of SILValues of captured
  /// arguments along with their symbolic values when available.
  /// \param allocator the allocator to use for storing the contents of this
  /// symbolic value.
  static SymbolicValue makeClosure(
      SILFunction *target,
      ArrayRef<std::pair<SILValue, Optional<SymbolicValue>>> capturedArguments,
      SubstitutionMap substMap, SingleValueInstruction *closureInst,
      SymbolicValueAllocator &allocator);

  SymbolicClosure *getClosure() const {
    assert(getKind() == Closure);
    return value.closure;
  }

  //===--------------------------------------------------------------------===//
  // Helpers

  /// Dig through single element aggregates, return the ultimate thing inside of
  /// it.  This is useful when dealing with integers and floats, because they
  /// are often wrapped in single-element struct wrappers.
  SymbolicValue lookThroughSingleElementAggregates() const;

  /// Given that this is an 'Unknown' value, emit diagnostic notes providing
  /// context about what the problem is.  If there is no location for some
  /// reason, we fall back to using the specified location.
  void emitUnknownDiagnosticNotes(SILLocation fallbackLoc);

  bool isUnknownDueToUnevaluatedInstructions();

  /// Clone this SymbolicValue into the specified Allocator and return the new
  /// version. This only works for valid constants.
  SymbolicValue cloneInto(SymbolicValueAllocator &allocator) const;

  void print(llvm::raw_ostream &os, unsigned indent = 0) const;
  void dump() const;
};

static_assert(sizeof(SymbolicValue) == 2 * sizeof(uint64_t),
              "SymbolicValue should stay small");
static_assert(std::is_trivial<SymbolicValue>::value,
              "SymbolicValue should stay trivial");

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, SymbolicValue val) {
  val.print(os);
  return os;
}

/// This is a representation of a memory object referred to by an address.
/// Memory objects may be mutated over their lifetime, but their overall type
/// remains the same.
struct SymbolicValueMemoryObject {
  Type getType() const { return type; }

  SymbolicValue getValue() const { return value; }
  void setValue(SymbolicValue newValue) {
    assert((newValue.getKind() != SymbolicValue::Aggregate ||
            newValue.getAggregateType()->isEqual(type)) &&
           "Memory object type does not match the type of the symbolic value");
    value = newValue;
  }

  /// Create a new memory object whose overall type is as specified.
  static SymbolicValueMemoryObject *create(Type type, SymbolicValue value,
                                           SymbolicValueAllocator &allocator);

  /// Given that this memory object contains an aggregate value like
  /// {{1, 2}, 3}, and given an access path like [0,1], return the indexed
  /// element, e.g. "2" in this case.
  ///
  /// Returns uninit memory if the access path points at or into uninit memory.
  ///
  /// Precondition: The access path must be valid for this memory object's type.
  SymbolicValue getIndexedElement(ArrayRef<unsigned> accessPath);

  /// Given that this memory object contains an aggregate value like
  /// {{1, 2}, 3}, given an access path like [0,1], and given a new element like
  /// "4", set the indexed element to the specified scalar, producing {{1, 4},
  /// 3} in this case.
  ///
  /// Precondition: The access path must be valid for this memory object's type.
  void setIndexedElement(ArrayRef<unsigned> accessPath,
                         SymbolicValue newElement,
                         SymbolicValueAllocator &allocator);

private:
  const Type type;
  SymbolicValue value;

  SymbolicValueMemoryObject(Type type, SymbolicValue value)
      : type(type), value(value) {}
  SymbolicValueMemoryObject(const SymbolicValueMemoryObject &) = delete;
  void operator=(const SymbolicValueMemoryObject &) = delete;
};

using SymbolicClosureArgument = std::pair<SILValue, Optional<SymbolicValue>>;

/// Representation of a symbolic closure. A symbolic closure consists of a
/// SILFunction and an array of SIL values, corresponding to the captured
/// arguments, and (optional) symbolic values representing the constant values
/// of the captured arguments. The symbolic values are optional as it is not
/// necessary for every captured argument to be a constant, which enables
/// representing closures whose captured arguments are not compile-time
/// constants.
struct SymbolicClosure final
  : private llvm::TrailingObjects<SymbolicClosure, SymbolicClosureArgument> {

  friend class llvm::TrailingObjects<SymbolicClosure, SymbolicClosureArgument>;

private:

  SILFunction *target;

  // The number of SIL values captured by the closure.
  unsigned numCaptures;

  // True iff there exists a captured argument whose constant value is not
  // known.
  bool hasNonConstantCaptures = true;

  // A substitution map that partially maps the generic paramters of the
  // applied function to the generic arguments of passed to the call.
  SubstitutionMap substitutionMap;

  // The closure instruction such as partial apply that resulted in this
  // symbolic value. This is tracked to obtain SILType and other SIL-level
  // information of the symbolic closure.
  SingleValueInstruction *closureInst;

  SymbolicClosure() = delete;
  SymbolicClosure(const SymbolicClosure &) = delete;
  SymbolicClosure(SILFunction *callee, unsigned numArguments,
                  SubstitutionMap substMap, SingleValueInstruction *inst,
                  bool nonConstantCaptures)
      : target(callee), numCaptures(numArguments),
        hasNonConstantCaptures(nonConstantCaptures), substitutionMap(substMap),
        closureInst(inst) {}

public:
  static SymbolicClosure *create(SILFunction *callee,
                                 ArrayRef<SymbolicClosureArgument> args,
                                 SubstitutionMap substMap,
                                 SingleValueInstruction *closureInst,
                                 SymbolicValueAllocator &allocator);

  ArrayRef<SymbolicClosureArgument> getCaptures() const {
    return {getTrailingObjects<SymbolicClosureArgument>(), numCaptures};
  }

  // This is used by the llvm::TrailingObjects base class.
  size_t numTrailingObjects(OverloadToken<SymbolicClosureArgument>) const {
    return numCaptures;
  }

  SILFunction *getTarget() {
    return target;
  }

  SingleValueInstruction *getClosureInst() { return closureInst; }

  SILType getClosureType() { return closureInst->getType(); }

  SubstitutionMap getCallSubstitutionMap() { return substitutionMap; }

  bool hasOnlyConstantCaptures() { return !hasNonConstantCaptures; }
};

} // end namespace swift

#endif