Repository: carbon-language/carbon-lang
File: toolchain/sem_ir/inst_kind.h (C/C++)

Code before:
  // constant value will instead be a `BoolLiteral`, and if its operand is not a
  // concrete constant, the result is non-constant. This is the default.
  Indirect,
  // This instruction may represent a symbolic constant, depending on its
  // operands, but never a concrete constant. For example, a `Call` instruction
  // can represent a symbolic constant but never a concrete constant. The
  // instruction may have a concrete constant value of a different kind.
  SymbolicOnly,
  // This instruction is a metaprogramming or template instantiation action that
  // generates an instruction. Like `SymbolicOnly`, it may represent a symbolic
  // constant, depending on its operands, but never represents a concrete
  // constant. The instruction may have a concrete constant value that is a
  // generated instruction. Constant evaluation support for types with this
  // constant kind is provided automatically, by calling `PerformDelayedAction`.
  InstAction,
  // This instruction can represent a symbolic or concrete constant, but might
  // not have a constant value, might have a constant value that is not defined
  // by itself, or might result in a compile-time error, depending on its
  // operands. For example, `ArrayType` is a compile-time constant if its
  // operands are constant and its array bound is within a valid range.
  Conditional,
  // This instruction represents a symbolic or concrete constant whenever its
  // operands are constant. Otherwise, it is non-constant. For example, a
  // `TupleValue` represents a constant if and only if its operands represent
  // constants. Constant evaluation support for types with this constant kind is
  // provided automatically.
  WheneverPossible,
  // This instruction always represents a constant value. This is the same as
  // `WheneverPossible`, except that the operands are known in advance to always
  // be constant. For example, `IntValue`.
  Always,
  // This instruction always represents a unique constant value, meaning that if
  // two instructions of this kind have different IDs, they represent different
  // constant values, even if they have the same arguments. This is used for
  // declarations whose constant identity is simply themselves. The `ConstantId`
  // for this instruction will always be a concrete constant whose `InstId`
  // refers directly back to the instruction, rather than to a separate
  // instruction in the constants block.
  // TODO: Decide if this is the model we want for these cases.
  Unique,
};

// Whether constant evaluation of an instruction needs the instruction to have
// been created and allocated an InstId, or only needs the instruction operands.
enum class InstConstantNeedsInstIdKind : int8_t {
  // This instruction kind doesn't need an InstId to be evaluated.
  No,
  // This instruction needs an InstId during evaluation, but doesn't need the
  // instruction to persist after evaluation.
  DuringEvaluation,
  // This instruction needs a permanent instruction ID, for example because that

Review comment (bug):
I think the pre-existing description here is wrong. How about this:
```suggestion
  // This instruction can represent a symbolic or concrete constant, and has a
  // constant value of the same kind whenever its operands are constant.
  // Otherwise, it is non-constant. For example, a `TupleValue` has a constant
  // value if and only if its operands have constant values, and its constant
  // value is always represented by a `TupleValue` instruction. Constant
  // evaluation support for types with this constant kind is provided
  // automatically.
```

Code after:
  // operands, and may be a concrete constant inst if it is a reference
  // expression, but it is never a concrete constant if it is a value or
  // initializing expression. For example, a `TupleAccess` instruction can be a
  // symbolic constant inst when applied to a symbolic constant, and can be a
  // concrete reference constant inst when applied to a reference constant.
  SymbolicOrReference,
  // This instruction is a metaprogramming or template instantiation action that
  // generates an instruction. Like `SymbolicOnly`, it may be a symbolic
  // constant inst depending on its operands, but never a concrete constant
  // inst. The instruction may have a concrete constant value that is a
  // generated instruction. Constant evaluation support for types with this
  // constant kind is provided automatically, by calling `PerformDelayedAction`.
  InstAction,
  // This instruction's operands determine whether it has a constant value,
  // whether it is a constant inst, and/or whether it results in a compile-time
  // error, in ways not expressed by the other InstConstantKinds. For example,
  // `ArrayType` is a compile-time constant if its operands are constant and its
  // array bound is within a valid range, and `ConstType` is a constant inst if
  // its operand is the canonical ID of a constant inst that isn't a
  // `ConstType`.
  Conditional,
  // This instruction is a constant inst if and only if its operands are all the
  // canonical IDs of constant insts, it has a constant value if and only if its
  // operands all have constant values, and that constant value is the result of
  // substituting the operands with their canonical IDs. For example, a
  // `TupleValue` has all these properties. Constant evaluation support for
  // types with this constant kind is provided automatically.
  WheneverPossible,
  // The same as `WheneverPossible`, except that the operands are known in
  // advance to always have a constant value. For example, `IntValue`.
  Always,
  // The instruction may be a unique constant, as described below for
  // `AlwaysUnique`. Otherwise the instruction is not constant. This is used for
  // `VarStorage`, where global variables are `AlwaysUnique` and other variables
  // are non-constant.
  ConditionalUnique,
  // This instruction is itself a unique constant, and its ID is always
  // canonical. This is used for declarations whose constant identity is simply
  // themselves. The `ConstantId` for this instruction will always be a concrete
  // constant whose `InstId` refers directly back to the instruction, rather
  // than to a separate instruction in the constants block.
  // TODO: Decide if this is the model we want for these cases.
  AlwaysUnique,
};

// Whether constant evaluation of an instruction needs the instruction to have
// been created and allocated an InstId, or only needs the instruction operands.
enum class InstConstantNeedsInstIdKind : int8_t {
  // This instruction kind doesn't need an InstId to be evaluated.
  No,
  // This instruction needs an InstId during evaluation, but doesn't need the