diff --git a/src/clone_context.cc b/src/clone_context.cc index 993431eb03..ed85d49453 100644 --- a/src/clone_context.cc +++ b/src/clone_context.cc @@ -69,6 +69,42 @@ ast::FunctionList CloneContext::Clone(const ast::FunctionList& v) { return out; } +tint::Cloneable* CloneContext::CloneCloneable(Cloneable* object) { + // If the input is nullptr, there's nothing to clone - just return nullptr. + if (object == nullptr) { + return nullptr; + } + + // Was Replace() called for this object? + auto it = replacements_.find(object); + if (it != replacements_.end()) { + return it->second(); + } + + // Attempt to clone using the registered replacer functions. + auto& typeinfo = object->TypeInfo(); + for (auto& transform : transforms_) { + if (typeinfo.Is(*transform.typeinfo)) { + if (auto* transformed = transform.function(object)) { + return transformed; + } + break; + } + } + + // No transform for this type, or the transform returned nullptr. + // Clone with T::Clone(). + return object->Clone(this); +} + +void CloneContext::CheckedCastFailure(Cloneable* got, + const TypeInfo& expected) { + TINT_ICE(Clone, Diagnostics()) + << "Cloned object was not of the expected type\n" + << "got: " << got->TypeInfo().name << "\n" + << "expected: " << expected.name; +} + diag::List& CloneContext::Diagnostics() const { return dst->Diagnostics(); } diff --git a/src/clone_context.h b/src/clone_context.h index c5437a59b7..4f72d2f420 100644 --- a/src/clone_context.h +++ b/src/clone_context.h @@ -24,6 +24,7 @@ #include "src/castable.h" #include "src/debug.h" +#include "src/program_id.h" #include "src/symbol.h" #include "src/traits.h" @@ -39,7 +40,7 @@ class Node; } // namespace ast ProgramID ProgramIDOf(const Program*); -ProgramID ProgramIDOf(const ast::Node*); +ProgramID ProgramIDOf(const ProgramBuilder*); /// Cloneable is the base class for all objects that can be cloned class Cloneable : public Castable { @@ -93,50 +94,19 @@ class CloneContext { /// If the CloneContext is cloning from a Program to a ProgramBuilder, then /// the Node or sem::Type `a` must be owned by the Program #src. /// - /// @param a the `Node` or `sem::Type` to clone + /// @param object the type deriving from Cloneable to clone /// @return the cloned node template - T* Clone(T* a) { - // If the input is nullptr, there's nothing to clone - just return nullptr. - if (a == nullptr) { - return nullptr; - } - + T* Clone(T* object) { if (src) { - TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, a); + TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, object); } - - // Was Replace() called for this object? - auto it = replacements_.find(a); - if (it != replacements_.end()) { - auto* replacement = it->second(); - TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, replacement); - return CheckedCast(replacement); + if (auto* cloned = CloneCloneable(object)) { + auto* out = CheckedCast(cloned); + TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, out); + return out; } - - Cloneable* cloned = nullptr; - - // Attempt to clone using the registered replacer functions. - auto& typeinfo = a->TypeInfo(); - for (auto& transform : transforms_) { - if (!typeinfo.Is(*transform.typeinfo)) { - continue; - } - cloned = transform.function(a); - break; - } - - if (!cloned) { - // No transform for this type, or the transform returned nullptr. - // Clone with T::Clone(). - cloned = a->Clone(this); - } - - auto* out = CheckedCast(cloned); - - TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, out); - - return out; + return nullptr; } /// Clones the Node or sem::Type `a` into the ProgramBuilder #dst if `a` is @@ -148,7 +118,7 @@ class CloneContext { /// If the CloneContext is cloning from a Program to a ProgramBuilder, then /// the Node or sem::Type `a` must be owned by the Program #src. /// - /// @param a the `Node` or `sem::Type` to clone + /// @param a the type deriving from Cloneable to clone /// @return the cloned node template T* CloneWithoutTransform(T* a) { @@ -519,20 +489,25 @@ class CloneContext { if (TO* cast = obj->template As()) { return cast; } - TINT_ICE(Clone, Diagnostics()) - << "Cloned object was not of the expected type\n" - << "got: " << obj->TypeInfo().name << "\n" - << "expected: " << TypeInfo::Of().name; + CheckedCastFailure(obj, TypeInfo::Of()); return nullptr; } + /// Clones a Cloneable object, using any replacements or transforms that have + /// been configured. + tint::Cloneable* CloneCloneable(Cloneable* object); + + /// Adds an error diagnostic to Diagnostics() that the cloned object was not + /// of the expected type. + void CheckedCastFailure(Cloneable* got, const TypeInfo& expected); + /// @returns the diagnostic list of #dst diag::List& Diagnostics() const; /// A vector of Cloneable* using CloneableList = std::vector; - // Transformations to be applied to a list (vector) + /// Transformations to be applied to a list (vector) struct ListTransforms { /// Constructor ListTransforms(); diff --git a/src/clone_context_test.cc b/src/clone_context_test.cc index 391c7c6026..e3720cb6d9 100644 --- a/src/clone_context_test.cc +++ b/src/clone_context_test.cc @@ -844,7 +844,7 @@ TEST_F(CloneContextTest, ProgramIDs_Clone_ObjectNotOwnedBySrc) { Allocator allocator; ctx.Clone(allocator.Create(ProgramID::New(), dst.ID())); }, - R"(internal compiler error: TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, a))"); + R"(internal compiler error: TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, object))"); } TEST_F(CloneContextTest, ProgramIDs_Clone_ObjectNotOwnedByDst) {