LibGC: Add a Variant overload to Cell::Visitor

This requires the Variant to contain at least one visitable type.
For example, requiring them all to be visitable wouldn't allow types
such as `Variant<Empty, GC::Ref<Document>>`.
This commit is contained in:
Luke Wilde 2026-05-07 21:20:04 +02:00 committed by Shannon Booth
parent 33a5f4868d
commit 369ed74bd1
2 changed files with 39 additions and 0 deletions

View file

@ -198,6 +198,16 @@ public:
void visit(NanBoxedValue const& value);
template<typename... Ts>
void visit(Variant<Ts...> const& variant)
requires((IsVisitable<Ts>::value || ...))
{
variant.visit([&](auto const& value) {
if constexpr (requires { visit(value); })
visit(value);
});
}
// Allow explicitly ignoring a GC-allocated member in a visit_edges implementation instead
// of just not using it.
template<typename T>

View file

@ -8,6 +8,7 @@
#include <AK/HashMap.h>
#include <AK/HashTable.h>
#include <AK/Optional.h>
#include <AK/Variant.h>
#include <AK/Vector.h>
#include <LibGC/Cell.h>
#include <LibGC/CellAllocator.h>
@ -339,6 +340,31 @@ TEST_CASE(visit_vector_of_nan_boxed_values_routes_to_visit_impl)
EXPECT_EQ(visitor.last_nan_span_size, 4u);
}
TEST_CASE(visit_variant_traces_active_cell_alternative)
{
auto& heap = test_heap();
auto cell = heap.allocate<TestCell>();
Variant<GC::Ref<TestCell>, int> variant { GC::Ref<TestCell>(cell) };
TestVisitor visitor;
visitor.visit(variant);
EXPECT(visitor.visited_cells.contains(cell.ptr()));
}
TEST_CASE(visit_variant_skips_untraced_alternative)
{
auto& heap = test_heap();
auto cell = heap.allocate<TestCell>();
Variant<GC::Ref<TestCell>, int> variant { 42 };
TestVisitor visitor;
visitor.visit(variant);
EXPECT_EQ(visitor.visited_cells.size(), 0u);
EXPECT(!visitor.visited_cells.contains(cell.ptr()));
}
static_assert(GC::IsVisitable<Vector<GC::Ref<TestCell>>>::value);
static_assert(GC::IsVisitable<Span<GC::Ref<TestCell>>>::value);
static_assert(GC::IsVisitable<ReadonlySpan<GC::Ref<TestCell>>>::value);
@ -354,3 +380,6 @@ static_assert(!GC::IsVisitable<ReadonlySpan<int>>::value);
static_assert(!GC::IsVisitable<HashTable<int>>::value);
static_assert(!GC::IsVisitable<OrderedHashTable<int>>::value);
static_assert(!GC::IsVisitable<Optional<int>>::value);
static_assert(GC::IsVisitable<Variant<GC::Ref<TestCell>, int>>::value);
static_assert(!GC::IsVisitable<Variant<int, double>>::value);