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

Code before:
    return LocIdAndInst::UncheckedLoc(LocId(inst_id), Get(inst_id));
  }

  // Returns whether the requested instruction is the specified type.
  template <typename InstT>
  auto Is(InstId inst_id) const -> bool {
    return Get(inst_id).Is<InstT>();
  }

  // Returns the requested instruction, which is known to have the specified
  // type.
  template <typename InstT>
  auto GetAs(InstId inst_id) const -> InstT {
    return Get(inst_id).As<InstT>();
  }

  // Returns the requested instruction as the specified type, if it is of that
  // type.
  template <typename InstT>
  auto TryGetAs(InstId inst_id) const -> std::optional<InstT> {
    return Get(inst_id).TryAs<InstT>();
  }

  // Use `GetAs()` when the instruction type is known.
  template <typename InstT>
  auto TryGetAs(KnownInstId<InstT> inst_id) const = delete;

  // Returns the requested instruction as the specified type, if it is valid and
  // of that type. Otherwise returns nullopt.
  template <typename InstT>
  auto TryGetAsIfValid(InstId inst_id) const -> std::optional<InstT> {
    if (!inst_id.has_value()) {
      return std::nullopt;
    }
    return TryGetAs<InstT>(inst_id);
  }

  template <class InstT>
  struct GetAsWithIdResult {
    SemIR::KnownInstId<InstT> inst_id;
    InstT inst;
  };

  // Returns the requested instruction, which is known to have the specified
  // type, along with the original `InstId`, encoding the work of checking its
  // type in a `KnownInstId`.
  template <typename InstT>
  auto GetAsWithId(InstId inst_id) const -> GetAsWithIdResult<InstT> {
    auto inst = GetAs<InstT>(inst_id);
    return {.inst_id = SemIR::KnownInstId<InstT>::UnsafeMake(inst_id),
            .inst = inst};

Review comment (suggestion):
It looks like this is only deleting the case where the known type and the requested type are the same -- is that your intent? Deleting the other case, when they're known-different (or returning `std::nullopt_t` there), seems more interesting to me.

Code after:
  // Returns the type of the instruction as an attached type.
  auto GetAttachedType(InstId inst_id) const -> TypeId {
    return GetWithAttachedType(inst_id).type_id();
  }

  // Returns the requested instruction and its location ID.
  auto GetWithLocId(InstId inst_id) const -> LocIdAndInst {
    return LocIdAndInst::UncheckedLoc(LocId(inst_id), Get(inst_id));
  }

  // Returns whether the requested instruction is the specified type.
  template <typename InstT>
  auto Is(InstId inst_id) const -> bool {
    return Get(inst_id).Is<InstT>();
  }

  // Returns the requested instruction, which is known to have the specified
  // type.
  template <typename InstT>
  auto GetAs(InstId inst_id) const -> InstT {
    return Get(inst_id).As<InstT>();
  }

  // Returns the requested instruction as the specified type, if it is of that
  // type.
  template <typename InstT>
  auto TryGetAs(InstId inst_id) const -> std::optional<InstT> {
    return Get(inst_id).TryAs<InstT>();
  }

  // Use `Get()` when the instruction type is known.
  template <typename InstT, typename KnownInstT>
  auto TryGetAs(KnownInstId<KnownInstT> inst_id) const = delete;

  // Returns the requested instruction as the specified type, if it is valid and
  // of that type. Otherwise returns nullopt.
  template <typename InstT>
  auto TryGetAsIfValid(InstId inst_id) const -> std::optional<InstT> {
    if (!inst_id.has_value()) {
      return std::nullopt;
    }
    return TryGetAs<InstT>(inst_id);
  }

  template <class InstT>
  struct GetAsWithIdResult {
    SemIR::KnownInstId<InstT> inst_id;
    InstT inst;
  };

  // Returns the requested instruction, which is known to have the specified