Repository: carbon-language/carbon-lang
File: toolchain/sem_ir/builtin_function_kind.cpp (C++)

Code before:
using PrimitiveCopyParamT = TypeParam<0, PrimitiveCopyable>;

// Not a builtin function.
constexpr BuiltinInfo None = {"", nullptr};

constexpr BuiltinInfo NoOp = {"no_op", ValidateNoOpSignature};

constexpr BuiltinInfo PrimitiveCopy = {
    "primitive_copy",
    ValidateSignature<auto(PrimitiveCopyParamT)->PrimitiveCopyParamT>};

// Prints a single character.
constexpr BuiltinInfo PrintChar = {
    "print.char", ValidateSignature<auto(AnySizedInt)->AnySizedInt>};

// Prints an integer.
constexpr BuiltinInfo PrintInt = {
    "print.int", ValidateSignature<auto(AnySizedInt)->NoReturn>};

// Reads a single character from stdin.
constexpr BuiltinInfo ReadChar = {"read.char",
                                  ValidateSignature<auto()->AnySizedInt>};

// Gets a character from a string at the given index.
constexpr BuiltinInfo StringAt = {
    "string.at", ValidateSignature<auto(AnyType, AnySizedInt)->AnySizedInt>};

// Returns the `Core.CharLiteral` type.
constexpr BuiltinInfo CharLiteralMakeType = {"char_literal.make_type",
                                             ValidateSignature<auto()->Type>};

// Returns the `Core.IntLiteral` type.
constexpr BuiltinInfo IntLiteralMakeType = {"int_literal.make_type",
                                            ValidateSignature<auto()->Type>};

// Returns the `Core.FloatLiteral` type.
constexpr BuiltinInfo FloatLiteralMakeType = {"float_literal.make_type",
                                              ValidateSignature<auto()->Type>};

// Returns the `iN` type.
// TODO: Should we use a more specific type as the type of the bit width?
constexpr BuiltinInfo IntMakeTypeSigned = {
    "int.make_type_signed", ValidateSignature<auto(AnyInt)->Type>};

// Returns the `uN` type.
constexpr BuiltinInfo IntMakeTypeUnsigned = {
    "int.make_type_unsigned", ValidateSignature<auto(AnyInt)->Type>};

// Returns float types, such as `f64`. Currently only supports `f64`.
constexpr BuiltinInfo FloatMakeType = {"float.make_type",
                                       ValidateSignature<auto(AnyInt)->Type>};

Review comment (bug):
Can we validate that the first parameter is a ClassType of Core.String? And we could write a test with an incorrect type that fails?

Code after:
// To constrain that the same type is used in multiple places in the signature,
// `TypeParam<I, T>` can be used. For example:
//
//   auto (TypeParam<0, AnyInt>, AnyInt) -> TypeParam<0, AnyInt>
//
// describes a builtin that takes two integers, and whose return type matches
// its first parameter type. For convenience, typedefs for `TypeParam<I, T>`
// are used in the descriptions of the builtins.
template <typename SignatureFnType>
static auto ValidateSignature(const File& sem_ir,
                              llvm::ArrayRef<InstId> call_params,
                              TypeId return_type) -> bool {
  using SignatureTraits = llvm::function_traits<SignatureFnType*>;
  ValidateState state;

  // Must have expected number of arguments.
  if (call_params.size() != SignatureTraits::num_args) {
    return false;
  }

  // Argument types must match.
  if (![&]<size_t... Indexes>(std::index_sequence<Indexes...>) {
        return ((CheckParam<typename SignatureTraits::template arg_t<Indexes>>(
                    sem_ir, state, call_params[Indexes])) &&
                ...);
      }(std::make_index_sequence<SignatureTraits::num_args>())) {
    return false;
  }

  // Result type must match.
  if (!CheckType<typename SignatureTraits::result_t>(sem_ir, state,
                                                     return_type)) {
    return false;
  }

  return true;
}

// Validates the signature for NoOp. This ignores all arguments, only validating
// that the return type is compatible.
static auto ValidateNoOpSignature(const File& sem_ir,
                                  llvm::ArrayRef<InstId> /*call_params*/,
                                  TypeId return_type) -> bool {
  ValidateState state;
  return CheckType<NoReturn>(sem_ir, state, return_type);
}

// Descriptions of builtin functions follow. For each builtin, a corresponding
// `BuiltinInfo` constant is declared describing properties of that builtin.
namespace BuiltinFunctionInfo {