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

Code before:
                    .Case("Float", Float)
                    .Default(None);
    if (kind == None) {
      return NumericTypeLiteralInfo::Invalid;
    }

    // There must be exactly one argument.
    const auto& specific = file.specifics().Get(class_type.specific_id);
    auto args = file.inst_blocks().Get(specific.args_id);
    if (args.size() != 1) {
      return NumericTypeLiteralInfo::Invalid;
    }

    // And the argument must be an integer value.
    auto width_arg = file.insts().TryGetAs<IntValue>(args[0]);
    if (!width_arg) {
      return NumericTypeLiteralInfo::Invalid;
    }
    return {.kind = kind, .bit_width_id = width_arg->int_id};
  }

  auto parent_name_ident =
      file.names().GetAsStringIfIdentifier(parent_scope_name_id);
  if (parent_name_ident == "CppCompat") {
    return llvm::StringSwitch<NumericTypeLiteralInfo>(*name_ident)
        .Case("Long32", {Int, IntId::MakeRaw(32)})
        .Default(NumericTypeLiteralInfo::Invalid);
  }

  return NumericTypeLiteralInfo::Invalid;
}

auto NumericTypeLiteralInfo::PrintLiteral(const File& file,
                                          llvm::raw_ostream& out) const
    -> void {
  CARBON_CHECK(is_valid());
  out << static_cast<char>(kind);
  file.ints().Get(bit_width_id).print(out, /*isSigned=*/false);
}

auto NumericTypeLiteralInfo::GetLiteralAsString(const File& file) const
    -> std::string {
  RawStringOstream out;
  PrintLiteral(file, out);
  return out.TakeStr();
}

auto TypeLiteralInfo::ForType(const File& file, ClassType class_type)
    -> TypeLiteralInfo {
  // The class must be declared in the `Core` package. We check for up to one
  // level of enclosing namespace.

Review comment (bug):
This shouldn't map to a `NumericTypeLiteralInfo` with value (`Int`, 32) because that means `i32`, not some other type that's also a 32-bit integer. We also don't have a literal syntax for `Core.Long32`, so treating it as a numeric type literal is probably not the right approach.

Let's add a `TypeLiteralInfo::Kind` value for it instead. We should also rename `TypeLiteralInfo` to something more like `RecognizedTypeInfo`, since we're using it for cases that aren't literals, such as `Core.CppCompat.NullptrT` and now `Core.CppCompat.[U]Long*`, but best not to do that in this PR I think.

Code after:
                  .Case("Int", Int)
                  .Case("UInt", UInt)
                  .Case("Float", Float)
                  .Default(None);
  if (kind == None) {
    return NumericTypeLiteralInfo::Invalid;
  }

  // There must be exactly one argument.
  const auto& specific = file.specifics().Get(class_type.specific_id);
  auto args = file.inst_blocks().Get(specific.args_id);
  if (args.size() != 1) {
    return NumericTypeLiteralInfo::Invalid;
  }

  // And the argument must be an integer value.
  auto width_arg = file.insts().TryGetAs<IntValue>(args[0]);
  if (!width_arg) {
    return NumericTypeLiteralInfo::Invalid;
  }
  return {.kind = kind, .bit_width_id = width_arg->int_id};
}

auto NumericTypeLiteralInfo::PrintLiteral(const File& file,
                                          llvm::raw_ostream& out) const
    -> void {
  CARBON_CHECK(is_valid());
  out << static_cast<char>(kind);
  file.ints().Get(bit_width_id).print(out, /*isSigned=*/false);
}

auto NumericTypeLiteralInfo::GetLiteralAsString(const File& file) const
    -> std::string {
  RawStringOstream out;
  PrintLiteral(file, out);
  return out.TakeStr();
}

auto TypeLiteralInfo::ForType(const File& file, ClassType class_type)
    -> TypeLiteralInfo {
  if (class_type.specific_id.has_value()) {
    auto numeric = NumericTypeLiteralInfo::ForType(file, class_type);
    if (numeric.is_valid()) {
      return {.kind = Numeric, .numeric = numeric};
    }
    return {.kind = None};
  }

  // The class must be declared in the `Core` package. We check for up to one
  // level of enclosing namespace.
  const auto& class_info = file.classes().Get(class_type.class_id);