Просмотр исходного кода

Simplify diagnostic conversion. (#3817)

Remove the enum of converted types, and use `llvm::any_cast` to
determine the type instead.
Richard Smith 2 лет назад
Родитель
Сommit
d52ea8390a

+ 7 - 13
toolchain/check/check.cpp

@@ -72,20 +72,14 @@ class SemIRDiagnosticConverter : public DiagnosticConverter<SemIRLocation> {
     }
   }
 
-  auto ConvertArg(DiagnosticTypeConversion conversion, llvm::Any arg) const
-      -> llvm::Any override {
-    switch (conversion) {
-      case DiagnosticTypeConversion::NameId: {
-        auto name_id = llvm::any_cast<SemIR::NameId>(arg);
-        return sem_ir_->names().GetFormatted(name_id).str();
-      }
-      case DiagnosticTypeConversion::TypeId: {
-        auto type_id = llvm::any_cast<SemIR::TypeId>(arg);
-        return sem_ir_->StringifyType(type_id);
-      }
-      default:
-        return DiagnosticConverter<SemIRLocation>::ConvertArg(conversion, arg);
+  auto ConvertArg(llvm::Any arg) const -> llvm::Any override {
+    if (auto* name_id = llvm::any_cast<SemIR::NameId>(&arg)) {
+      return sem_ir_->names().GetFormatted(*name_id).str();
+    }
+    if (auto* type_id = llvm::any_cast<SemIR::TypeId>(&arg)) {
+      return sem_ir_->StringifyType(*type_id);
     }
+    return DiagnosticConverter<SemIRLocation>::ConvertArg(arg);
   }
 
  private:

+ 9 - 29
toolchain/diagnostics/diagnostic_converter.h

@@ -5,23 +5,11 @@
 #ifndef CARBON_TOOLCHAIN_DIAGNOSTICS_DIAGNOSTIC_CONVERTER_H_
 #define CARBON_TOOLCHAIN_DIAGNOSTICS_DIAGNOSTIC_CONVERTER_H_
 
-#include <cstdint>
-
-#include "common/check.h"
 #include "llvm/ADT/Any.h"
 #include "toolchain/diagnostics/diagnostic.h"
 
 namespace Carbon {
 
-// Known diagnostic type conversions. These are enumerated because `llvm::Any`
-// doesn't expose the contained type; instead, we infer it from a given
-// diagnostic.
-enum class DiagnosticTypeConversion : int8_t {
-  None,
-  NameId,
-  TypeId,
-};
-
 // An interface that can convert some representation of a location into a
 // diagnostic location.
 template <typename LocationT>
@@ -31,27 +19,21 @@ class DiagnosticConverter {
 
   virtual auto ConvertLocation(LocationT loc) const -> DiagnosticLocation = 0;
 
-  // Converts arg types as needed. Not all uses support conversion, so the
-  // default simply errors.
-  virtual auto ConvertArg(DiagnosticTypeConversion conversion,
-                          llvm::Any /*arg*/) const -> llvm::Any {
-    CARBON_FATAL() << "Unexpected call to ConvertArg: "
-                   << static_cast<int8_t>(conversion);
-  }
+  // Converts arg types as needed. Not all uses require conversion, so the
+  // default returns the argument unchanged.
+  virtual auto ConvertArg(llvm::Any arg) const -> llvm::Any { return arg; }
 };
 
-// Used by types to indicate a DiagnosticTypeConversion that results in the
+// Used by types to indicate a diagnostic type conversion that results in the
 // provided StorageType. For example, to convert NameId to a std::string, we
 // write:
 //
 // struct NameId {
-//   using DiagnosticType =
-//       DiagnosticTypeInfo<std::string, DiagnosticTypeConversion::NameId>;
+//   using DiagnosticType = DiagnosticTypeInfo<std::string>;
 // };
-template <typename StorageTypeT, DiagnosticTypeConversion ConversionV>
+template <typename StorageTypeT>
 struct DiagnosticTypeInfo {
   using StorageType = StorageTypeT;
-  static constexpr DiagnosticTypeConversion Conversion = ConversionV;
 };
 
 namespace Internal {
@@ -59,13 +41,11 @@ namespace Internal {
 // Determines whether there's a DiagnosticType member on Arg.
 // Used by DiagnosticEmitter.
 template <typename Arg>
-concept HasDiagnosticType =
-    requires { std::type_identity<typename Arg::DiagnosticType>(); };
+concept HasDiagnosticType = requires { typename Arg::DiagnosticType; };
 
 // The default implementation with no conversion.
-template <typename Arg, typename /*Unused*/ = void>
-struct DiagnosticTypeForArg
-    : public DiagnosticTypeInfo<Arg, DiagnosticTypeConversion::None> {};
+template <typename Arg>
+struct DiagnosticTypeForArg : public DiagnosticTypeInfo<Arg> {};
 
 // Exposes a custom conversion for an argument type.
 template <typename Arg>

+ 6 - 7
toolchain/diagnostics/diagnostic_emitter.h

@@ -167,13 +167,12 @@ class DiagnosticEmitter {
   // type conversion when needed.
   template <typename Arg>
   auto MakeAny(Arg arg) -> llvm::Any {
-    if constexpr (Internal::DiagnosticTypeForArg<Arg>::Conversion ==
-                  DiagnosticTypeConversion::None) {
-      return arg;
-    } else {
-      return converter_->ConvertArg(
-          Internal::DiagnosticTypeForArg<Arg>::Conversion, arg);
-    }
+    llvm::Any converted = converter_->ConvertArg(arg);
+    using Storage = Internal::DiagnosticTypeForArg<Arg>::StorageType;
+    CARBON_CHECK(llvm::any_cast<Storage>(&converted))
+        << "Failed to convert argument of type " << typeid(Arg).name()
+        << " to its storage type " << typeid(Storage).name();
+    return converted;
   }
 
   template <typename LocT, typename AnnotateFn>

+ 2 - 4
toolchain/sem_ir/ids.h

@@ -289,8 +289,7 @@ constexpr BoolValue BoolValue::True = BoolValue(1);
 // `self`, `Self`, or `base`.
 struct NameId : public IdBase, public Printable<NameId> {
   // names().GetFormatted() is used for diagnostics.
-  using DiagnosticType =
-      DiagnosticTypeInfo<std::string, DiagnosticTypeConversion::NameId>;
+  using DiagnosticType = DiagnosticTypeInfo<std::string>;
 
   // An explicitly invalid ID.
   static const NameId Invalid;
@@ -427,8 +426,7 @@ constexpr InstBlockId InstBlockId::GlobalInit = InstBlockId(2);
 struct TypeId : public IdBase, public Printable<TypeId> {
   using ValueType = TypeInfo;
   // StringifyType() is used for diagnostics.
-  using DiagnosticType =
-      DiagnosticTypeInfo<std::string, DiagnosticTypeConversion::TypeId>;
+  using DiagnosticType = DiagnosticTypeInfo<std::string>;
 
   // The builtin TypeType.
   static const TypeId TypeType;