mirror of
https://github.com/luau-lang/luau.git
synced 2024-11-15 22:35:43 +08:00
ce8495a69e
# What's Changed? - Code refactoring with a new clang-format - More bug fixes / test case fixes in the new solver ## New Solver - More precise telemetry collection of `any` types - Simplification of two completely disjoint tables combines them into a single table that inherits all properties / indexers - Refining a `never & <anything>` does not produce type family types nor constraints - Silence "inference failed to complete" error when it is the only error reported --- ### Internal Contributors Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Dibri Nsofor <dnsofor@roblox.com> Co-authored-by: Jeremy Yoo <jyoo@roblox.com> Co-authored-by: Vighnesh Vijay <vvijay@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> --------- Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Vighnesh <vvijay@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: David Cope <dcope@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
260 lines
5.6 KiB
C++
260 lines
5.6 KiB
C++
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
|
#include "Luau/Variant.h"
|
|
|
|
#include <string>
|
|
#include <ostream>
|
|
|
|
#include "doctest.h"
|
|
|
|
using namespace Luau;
|
|
|
|
struct Foo
|
|
{
|
|
int x = 42;
|
|
};
|
|
|
|
struct Bar
|
|
{
|
|
explicit Bar(int x)
|
|
: prop(x * 2)
|
|
{
|
|
++count;
|
|
}
|
|
|
|
~Bar()
|
|
{
|
|
--count;
|
|
}
|
|
|
|
int prop;
|
|
static int count;
|
|
};
|
|
|
|
int Bar::count = 0;
|
|
|
|
TEST_SUITE_BEGIN("Variant");
|
|
|
|
TEST_CASE("DefaultCtor")
|
|
{
|
|
Variant<int, Foo> v1;
|
|
Variant<Foo, int> v2;
|
|
|
|
REQUIRE(get_if<int>(&v1));
|
|
CHECK(*get_if<int>(&v1) == 0);
|
|
CHECK(!get_if<Foo>(&v1));
|
|
|
|
REQUIRE(get_if<Foo>(&v2));
|
|
CHECK(get_if<Foo>(&v2)->x == 42);
|
|
}
|
|
|
|
TEST_CASE("Create")
|
|
{
|
|
Variant<int, Foo> v1 = 1;
|
|
Variant<Foo, int> v2 = Foo{2};
|
|
|
|
Foo f = {3};
|
|
Variant<Foo, int> v3 = f;
|
|
|
|
REQUIRE(get_if<int>(&v1));
|
|
CHECK(*get_if<int>(&v1) == 1);
|
|
|
|
REQUIRE(get_if<Foo>(&v2));
|
|
CHECK(get_if<Foo>(&v2)->x == 2);
|
|
|
|
REQUIRE(get_if<Foo>(&v3));
|
|
CHECK(get_if<Foo>(&v3)->x == 3);
|
|
}
|
|
|
|
TEST_CASE("Emplace")
|
|
{
|
|
{
|
|
Variant<int, Bar> v1;
|
|
|
|
CHECK(0 == Bar::count);
|
|
int& i = v1.emplace<int>(5);
|
|
CHECK(5 == i);
|
|
|
|
CHECK(0 == Bar::count);
|
|
|
|
CHECK(get_if<int>(&v1) == &i);
|
|
|
|
Bar& bar = v1.emplace<Bar>(11);
|
|
CHECK(22 == bar.prop);
|
|
CHECK(1 == Bar::count);
|
|
|
|
CHECK(get_if<Bar>(&v1) == &bar);
|
|
}
|
|
|
|
CHECK(0 == Bar::count);
|
|
}
|
|
|
|
TEST_CASE("NonPOD")
|
|
{
|
|
// initialize (copy)
|
|
std::string s1 = "hello";
|
|
Variant<std::string, int> v1 = s1;
|
|
|
|
CHECK(*get_if<std::string>(&v1) == "hello");
|
|
|
|
// initialize (move)
|
|
Variant<std::string, int> v2 = std::string("hello");
|
|
|
|
CHECK(*get_if<std::string>(&v2) == "hello");
|
|
|
|
// move-assign
|
|
v2 = std::string("this is a long string that doesn't fit into the small buffer");
|
|
|
|
CHECK(*get_if<std::string>(&v2) == "this is a long string that doesn't fit into the small buffer");
|
|
|
|
// copy-assign
|
|
std::string s2("this is another long string, and this time we're copying it");
|
|
v2 = s2;
|
|
|
|
CHECK(*get_if<std::string>(&v2) == "this is another long string, and this time we're copying it");
|
|
|
|
// copy ctor
|
|
Variant<std::string, int> v3 = v2;
|
|
|
|
CHECK(*get_if<std::string>(&v2) == "this is another long string, and this time we're copying it");
|
|
CHECK(*get_if<std::string>(&v3) == "this is another long string, and this time we're copying it");
|
|
|
|
// move ctor
|
|
Variant<std::string, int> v4 = std::move(v3);
|
|
|
|
CHECK(*get_if<std::string>(&v2) == "this is another long string, and this time we're copying it");
|
|
CHECK(*get_if<std::string>(&v3) == ""); // moved-from variant has an empty string now
|
|
CHECK(*get_if<std::string>(&v4) == "this is another long string, and this time we're copying it");
|
|
}
|
|
|
|
TEST_CASE("Equality")
|
|
{
|
|
Variant<int, std::string> v1 = std::string("hi");
|
|
Variant<int, std::string> v2 = std::string("me");
|
|
Variant<int, std::string> v3 = 1;
|
|
Variant<int, std::string> v4 = 0;
|
|
Variant<int, std::string> v5;
|
|
|
|
CHECK(v1 == v1);
|
|
CHECK(v1 != v2);
|
|
CHECK(v1 != v3);
|
|
CHECK(v3 != v4);
|
|
CHECK(v4 == v5);
|
|
}
|
|
|
|
struct ToStringVisitor
|
|
{
|
|
std::string operator()(const std::string& v)
|
|
{
|
|
return v;
|
|
}
|
|
|
|
std::string operator()(int v)
|
|
{
|
|
return std::to_string(v);
|
|
}
|
|
};
|
|
|
|
struct IncrementVisitor
|
|
{
|
|
void operator()(std::string& v)
|
|
{
|
|
v += "1";
|
|
}
|
|
|
|
void operator()(int& v)
|
|
{
|
|
v += 1;
|
|
}
|
|
};
|
|
|
|
TEST_CASE("Visit")
|
|
{
|
|
Variant<std::string, int> v1 = std::string("123");
|
|
Variant<std::string, int> v2 = 45;
|
|
const Variant<std::string, int>& v1c = v1;
|
|
const Variant<std::string, int>& v2c = v2;
|
|
|
|
// void-returning visitor, const variants
|
|
std::string r1;
|
|
visit(
|
|
[&](const auto& v)
|
|
{
|
|
r1 += ToStringVisitor()(v);
|
|
},
|
|
v1c
|
|
);
|
|
visit(
|
|
[&](const auto& v)
|
|
{
|
|
r1 += ToStringVisitor()(v);
|
|
},
|
|
v2c
|
|
);
|
|
CHECK(r1 == "12345");
|
|
|
|
// value-returning visitor, const variants
|
|
std::string r2;
|
|
r2 += visit(ToStringVisitor(), v1c);
|
|
r2 += visit(ToStringVisitor(), v2c);
|
|
CHECK(r2 == "12345");
|
|
|
|
// void-returning visitor, mutable variant
|
|
visit(IncrementVisitor(), v1);
|
|
visit(IncrementVisitor(), v2);
|
|
CHECK(visit(ToStringVisitor(), v1) == "1231");
|
|
CHECK(visit(ToStringVisitor(), v2) == "46");
|
|
|
|
// value-returning visitor, mutable variant
|
|
std::string r3;
|
|
r3 += visit(
|
|
[&](auto& v)
|
|
{
|
|
IncrementVisitor()(v);
|
|
return ToStringVisitor()(v);
|
|
},
|
|
v1
|
|
);
|
|
r3 += visit(
|
|
[&](auto& v)
|
|
{
|
|
IncrementVisitor()(v);
|
|
return ToStringVisitor()(v);
|
|
},
|
|
v2
|
|
);
|
|
CHECK(r3 == "1231147");
|
|
}
|
|
|
|
struct MoveOnly
|
|
{
|
|
MoveOnly() = default;
|
|
|
|
MoveOnly(const MoveOnly&) = delete;
|
|
MoveOnly& operator=(const MoveOnly&) = delete;
|
|
|
|
MoveOnly(MoveOnly&&) = default;
|
|
MoveOnly& operator=(MoveOnly&&) = default;
|
|
};
|
|
|
|
TEST_CASE("Move")
|
|
{
|
|
Variant<MoveOnly> v1 = MoveOnly{};
|
|
Variant<MoveOnly> v2 = std::move(v1);
|
|
}
|
|
|
|
TEST_CASE("MoveWithCopyableAlternative")
|
|
{
|
|
Variant<std::string, MoveOnly> v1 = std::string{"Hello, world! I am longer than a normal hello world string to avoid SSO."};
|
|
Variant<std::string, MoveOnly> v2 = std::move(v1);
|
|
|
|
std::string* s1 = get_if<std::string>(&v1);
|
|
REQUIRE(s1);
|
|
CHECK(*s1 == "");
|
|
|
|
std::string* s2 = get_if<std::string>(&v2);
|
|
REQUIRE(s2);
|
|
CHECK(*s2 == "Hello, world! I am longer than a normal hello world string to avoid SSO.");
|
|
}
|
|
|
|
TEST_SUITE_END();
|