Răsfoiți Sursa

Refactor BuildCustomWitness out to its own file (#6515)

Per request at
https://github.com/carbon-language/carbon-lang/pull/6512#discussion_r2627265838
Jon Ross-Perkins 4 luni în urmă
părinte
comite
655932da0b

+ 2 - 0
toolchain/check/BUILD

@@ -34,6 +34,7 @@ cc_library(
         "cpp/overload_resolution.cpp",
         "cpp/thunk.cpp",
         "cpp/type_mapping.cpp",
+        "custom_witness.cpp",
         "decl_name_stack.cpp",
         "deduce.cpp",
         "deferred_definition_worklist.cpp",
@@ -91,6 +92,7 @@ cc_library(
         "cpp/overload_resolution.h",
         "cpp/thunk.h",
         "cpp/type_mapping.h",
+        "custom_witness.h",
         "decl_introducer_state.h",
         "decl_name_stack.h",
         "deduce.h",

+ 1 - 0
toolchain/check/cpp/impl_lookup.cpp

@@ -9,6 +9,7 @@
 #include "toolchain/check/cpp/import.h"
 #include "toolchain/check/cpp/location.h"
 #include "toolchain/check/cpp/overload_resolution.h"
+#include "toolchain/check/custom_witness.h"
 #include "toolchain/check/impl.h"
 #include "toolchain/check/impl_lookup.h"
 #include "toolchain/check/import_ref.h"

+ 94 - 0
toolchain/check/custom_witness.cpp

@@ -0,0 +1,94 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "toolchain/check/custom_witness.h"
+
+#include "toolchain/base/kind_switch.h"
+#include "toolchain/check/impl.h"
+#include "toolchain/check/import_ref.h"
+#include "toolchain/check/inst.h"
+#include "toolchain/check/type.h"
+
+namespace Carbon::Check {
+
+auto BuildCustomWitness(Context& context, SemIR::LocId loc_id,
+                        SemIR::TypeId self_type_id,
+                        SemIR::SpecificInterface specific_interface,
+                        llvm::ArrayRef<SemIR::InstId> values) -> SemIR::InstId {
+  const auto& interface =
+      context.interfaces().Get(specific_interface.interface_id);
+  auto assoc_entities =
+      context.inst_blocks().GetOrEmpty(interface.associated_entities_id);
+  if (assoc_entities.size() != values.size()) {
+    context.TODO(loc_id, ("Unsupported definition of interface " +
+                          context.names().GetFormatted(interface.name_id))
+                             .str());
+    return SemIR::ErrorInst::InstId;
+  }
+
+  llvm::SmallVector<SemIR::InstId> entries;
+
+  // Build a witness with the current contents of the witness table. This will
+  // grow as we progress through the impl. In theory this will build O(n^2)
+  // table entries, but in practice n <= 2, so that's OK.
+  //
+  // This is necessary because later associated entities may refer to earlier
+  // associated entities in their signatures. In particular, an associated
+  // result type may be used as the return type of an associated function.
+  //
+  // TODO: Consider building one witness after all associated constants, and
+  // then a second after all associated functions, rather than building one at
+  // each step. For now this doesn't really matter since we don't have more than
+  // one of each anyway.
+  auto make_witness = [&] {
+    return context.constant_values().GetInstId(
+        EvalOrAddInst<SemIR::CustomWitness>(
+            context, loc_id,
+            {.type_id =
+                 GetSingletonType(context, SemIR::WitnessType::TypeInstId),
+             .elements_id = context.inst_blocks().Add(entries)}));
+  };
+
+  // Fill in the witness table.
+  for (const auto& [assoc_entity_id, value_id] :
+       llvm::zip_equal(assoc_entities, values)) {
+    LoadImportRef(context, assoc_entity_id);
+    auto decl_id =
+        context.constant_values().GetInstId(SemIR::GetConstantValueInSpecific(
+            context.sem_ir(), specific_interface.specific_id, assoc_entity_id));
+    CARBON_CHECK(decl_id.has_value(), "Non-constant associated entity");
+    auto decl = context.insts().Get(decl_id);
+    CARBON_KIND_SWITCH(decl) {
+      case CARBON_KIND(SemIR::StructValue struct_value): {
+        if (struct_value.type_id == SemIR::ErrorInst::TypeId) {
+          return SemIR::ErrorInst::InstId;
+        }
+        // TODO: If a thunk is needed, this will build a different value each
+        // time it's called, so we won't properly deduplicate repeated
+        // witnesses.
+        // TODO: Skip calling make_witness if this function signature doesn't
+        // involve `Self`.
+        entries.push_back(CheckAssociatedFunctionImplementation(
+            context,
+            context.types().GetAs<SemIR::FunctionType>(struct_value.type_id),
+            value_id, self_type_id, make_witness(),
+            /*defer_thunk_definition=*/false));
+        break;
+      }
+      case SemIR::AssociatedConstantDecl::Kind: {
+        context.TODO(loc_id,
+                     "Associated constant in interface with synthesized impl");
+        return SemIR::ErrorInst::InstId;
+      }
+      default:
+        CARBON_CHECK(decl_id == SemIR::ErrorInst::InstId,
+                     "Unexpected kind of associated entity {0}", decl);
+        return SemIR::ErrorInst::InstId;
+    }
+  }
+
+  return make_witness();
+}
+
+}  // namespace Carbon::Check

+ 24 - 0
toolchain/check/custom_witness.h

@@ -0,0 +1,24 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef CARBON_TOOLCHAIN_CHECK_CUSTOM_WITNESS_H_
+#define CARBON_TOOLCHAIN_CHECK_CUSTOM_WITNESS_H_
+
+#include "toolchain/check/context.h"
+#include "toolchain/sem_ir/ids.h"
+
+namespace Carbon::Check {
+
+// Builds a witness that the given type implements the given interface,
+// populating it with the specified set of values. Returns a corresponding
+// lookup result. Produces a diagnostic and returns `None` if the specified
+// values aren't suitable for the interface.
+auto BuildCustomWitness(Context& context, SemIR::LocId loc_id,
+                        SemIR::TypeId self_type_id,
+                        SemIR::SpecificInterface specific_interface,
+                        llvm::ArrayRef<SemIR::InstId> values) -> SemIR::InstId;
+
+}  // namespace Carbon::Check
+
+#endif  // CARBON_TOOLCHAIN_CHECK_CUSTOM_WITNESS_H_

+ 0 - 79
toolchain/check/impl.cpp

@@ -724,83 +724,4 @@ auto CheckConstraintIsInterface(Context& context, SemIR::InstId impl_decl_id,
   return identified.impl_as_target_interface();
 }
 
-auto BuildCustomWitness(Context& context, SemIR::LocId loc_id,
-                        SemIR::TypeId self_type_id,
-                        SemIR::SpecificInterface specific_interface,
-                        llvm::ArrayRef<SemIR::InstId> values) -> SemIR::InstId {
-  const auto& interface =
-      context.interfaces().Get(specific_interface.interface_id);
-  auto assoc_entities =
-      context.inst_blocks().GetOrEmpty(interface.associated_entities_id);
-  if (assoc_entities.size() != values.size()) {
-    context.TODO(loc_id, ("Unsupported definition of interface " +
-                          context.names().GetFormatted(interface.name_id))
-                             .str());
-    return SemIR::ErrorInst::InstId;
-  }
-
-  llvm::SmallVector<SemIR::InstId> entries;
-
-  // Build a witness with the current contents of the witness table. This will
-  // grow as we progress through the impl. In theory this will build O(n^2)
-  // table entries, but in practice n <= 2, so that's OK.
-  //
-  // This is necessary because later associated entities may refer to earlier
-  // associated entities in their signatures. In particular, an associated
-  // result type may be used as the return type of an associated function.
-  //
-  // TODO: Consider building one witness after all associated constants, and
-  // then a second after all associated functions, rather than building one at
-  // each step. For now this doesn't really matter since we don't have more than
-  // one of each anyway.
-  auto make_witness = [&] {
-    return context.constant_values().GetInstId(
-        EvalOrAddInst<SemIR::CustomWitness>(
-            context, loc_id,
-            {.type_id =
-                 GetSingletonType(context, SemIR::WitnessType::TypeInstId),
-             .elements_id = context.inst_blocks().Add(entries)}));
-  };
-
-  // Fill in the witness table.
-  for (const auto& [assoc_entity_id, value_id] :
-       llvm::zip_equal(assoc_entities, values)) {
-    LoadImportRef(context, assoc_entity_id);
-    auto decl_id =
-        context.constant_values().GetInstId(SemIR::GetConstantValueInSpecific(
-            context.sem_ir(), specific_interface.specific_id, assoc_entity_id));
-    CARBON_CHECK(decl_id.has_value(), "Non-constant associated entity");
-    auto decl = context.insts().Get(decl_id);
-    CARBON_KIND_SWITCH(decl) {
-      case CARBON_KIND(SemIR::StructValue struct_value): {
-        if (struct_value.type_id == SemIR::ErrorInst::TypeId) {
-          return SemIR::ErrorInst::InstId;
-        }
-        // TODO: If a thunk is needed, this will build a different value each
-        // time it's called, so we won't properly deduplicate repeated
-        // witnesses.
-        // TODO: Skip calling make_witness if this function signature doesn't
-        // involve `Self`.
-        entries.push_back(CheckAssociatedFunctionImplementation(
-            context,
-            context.types().GetAs<SemIR::FunctionType>(struct_value.type_id),
-            value_id, self_type_id, make_witness(),
-            /*defer_thunk_definition=*/false));
-        break;
-      }
-      case SemIR::AssociatedConstantDecl::Kind: {
-        context.TODO(loc_id,
-                     "Associated constant in interface with synthesized impl");
-        return SemIR::ErrorInst::InstId;
-      }
-      default:
-        CARBON_CHECK(decl_id == SemIR::ErrorInst::InstId,
-                     "Unexpected kind of associated entity {0}", decl);
-        return SemIR::ErrorInst::InstId;
-    }
-  }
-
-  return make_witness();
-}
-
 }  // namespace Carbon::Check