luau/tests/ToString.test.cpp

1037 lines
32 KiB
C++
Raw Normal View History

// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Scope.h"
#include "Luau/ToString.h"
#include "Fixture.h"
#include "ScopedFlags.h"
#include "doctest.h"
using namespace Luau;
2022-04-15 07:57:43 +08:00
LUAU_FASTFLAG(LuauRecursiveTypeParameterRestriction);
Sync to upstream/release/588 (#992) Type checker/autocomplete: * `Luau::autocomplete` no longer performs typechecking internally, make sure to run `Frontend::check` before performing autocomplete requests * Autocomplete string suggestions without "" are now only suggested inside the "" * Autocomplete suggestions now include `function (anonymous autofilled)` key with a full suggestion for the function expression (with arguments included) stored in `AutocompleteEntry::insertText` * `AutocompleteEntry::indexedWithSelf` is provided for function call suggestions made with `:` * Cyclic modules now see each other type exports as `any` to prevent memory use-after-free (similar to module return type) Runtime: * Updated inline/loop unroll cost model to better handle assignments (Fixes https://github.com/Roblox/luau/issues/978) * `math.noise` speed was improved by ~30% * `table.concat` speed was improved by ~5-7% * `tonumber` and `tostring` now have fastcall paths that execute ~1.5x and ~2.5x faster respectively (fixes #777) * Fixed crash in `luaL_typename` when index refers to a non-existing value * Fixed potential out of memory scenario when using `string.sub` or `string.char` in a loop * Fixed behavior of some fastcall builtins when called without arguments under -O2 to match original functions * Support for native code execution in VM is now enabled by default (note: native code still has to be generated explicitly) * `Codegen::compile` now accepts `CodeGen_OnlyNativeModules` flag. When set, only modules that have a `--!native` hot-comment at the top will be compiled to native code In our new typechecker: * Generic type packs are no longer considered to be variadic during unification * Timeout and cancellation now works in new solver * Fixed false positive errors around 'table' and 'function' type refinements * Table literals now use covariant unification rules. This is sound since literal has no type specified and has no aliases * Fixed issues with blocked types escaping the constraint solver * Fixed more places where error messages that should've been suppressed were still reported * Fixed errors when iterating over a top table type In our native code generation (jit): * 'DebugLuauAbortingChecks' flag is now supported on A64 * LOP_NEWCLOSURE has been translated to IR
2023-07-28 23:13:53 +08:00
LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution);
Sync to upstream/release/605 (#1118) - Implemented [Require by String with Relative Paths](https://github.com/luau-lang/rfcs/blob/master/docs/new-require-by-string-semantics.md) RFC - Implemented [Require by String with Aliases](https://github.com/luau-lang/rfcs/blob/master/docs/require-by-string-aliases.md) RFC with support for `paths` and `alias` arrays in .luarc - Added SUBRK and DIVRK bytecode instructions to speed up constant-number and constant/number operations - Added `--vector-lib`, `--vector-ctor` and `--vector-type` options to luau-compile to support code with vectors New Solver - Correctness fixes to subtyping - Improvements to dataflow analysis Native Code Generation - Added bytecode analysis pass to predict type tags used in operations - Fixed rare cases of numerical loops being generated without an interrupt instruction - Restored optimization data propagation into the linear block - Duplicate buffer length checks are optimized away Miscellaneous - Small performance improvements to new non-strict mode - Introduced more scripts for fuzzing Luau and processing the results, including fuzzer build support for CMake Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@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: 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: 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>
2023-12-02 15:46:57 +08:00
LUAU_FASTFLAG(LuauCheckedFunctionSyntax);
LUAU_FASTFLAG(DebugLuauSharedSelf);
LUAU_FASTFLAG(LuauStringifyCyclesRootedAtPacks);
2022-04-15 07:57:43 +08:00
TEST_SUITE_BEGIN("ToString");
TEST_CASE_FIXTURE(Fixture, "primitive")
{
CheckResult result = check("local a = nil local b = 44 local c = 'lalala' local d = true");
LUAU_REQUIRE_NO_ERRORS(result);
// A variable without an annotation and with a nil literal should infer as 'free', not 'nil'
CHECK_NE("nil", toString(requireType("a")));
CHECK_EQ("number", toString(requireType("b")));
CHECK_EQ("string", toString(requireType("c")));
CHECK_EQ("boolean", toString(requireType("d")));
}
TEST_CASE_FIXTURE(Fixture, "bound_types")
{
CheckResult result = check("local a = 444 local b = a");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number", toString(requireType("b")));
}
TEST_CASE_FIXTURE(Fixture, "free_types")
{
CheckResult result = check("local a");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ("a", toString(requireType("a")));
}
TEST_CASE_FIXTURE(Fixture, "cyclic_table")
{
Type cyclicTable{TypeVariant(TableType())};
TableType* tableOne = getMutable<TableType>(&cyclicTable);
tableOne->props["self"] = {&cyclicTable};
if (FFlag::DebugLuauDeferredConstraintResolution)
CHECK_EQ("t1 where t1 = {| self: t1 |}", toString(&cyclicTable));
else
CHECK_EQ("t1 where t1 = { self: t1 }", toString(&cyclicTable));
}
TEST_CASE_FIXTURE(Fixture, "named_table")
{
Type table{TypeVariant(TableType())};
TableType* t = getMutable<TableType>(&table);
t->name = "TheTable";
CHECK_EQ("TheTable", toString(&table));
}
TEST_CASE_FIXTURE(Fixture, "empty_table")
{
CheckResult result = check(R"(
local a: {}
)");
if (FFlag::DebugLuauDeferredConstraintResolution)
CHECK_EQ("{ }", toString(requireType("a")));
else
CHECK_EQ("{| |}", toString(requireType("a")));
// Should stay the same with useLineBreaks enabled
ToStringOptions opts;
opts.useLineBreaks = true;
if (FFlag::DebugLuauDeferredConstraintResolution)
CHECK_EQ("{ }", toString(requireType("a"), opts));
else
CHECK_EQ("{| |}", toString(requireType("a"), opts));
}
TEST_CASE_FIXTURE(Fixture, "table_respects_use_line_break")
{
CheckResult result = check(R"(
local a: { prop: string, anotherProp: number, thirdProp: boolean }
)");
ToStringOptions opts;
opts.useLineBreaks = true;
//clang-format off
if (FFlag::DebugLuauDeferredConstraintResolution)
CHECK_EQ("{\n"
" anotherProp: number,\n"
" prop: string,\n"
" thirdProp: boolean\n"
"}",
toString(requireType("a"), opts));
else
CHECK_EQ("{|\n"
" anotherProp: number,\n"
" prop: string,\n"
" thirdProp: boolean\n"
"|}",
toString(requireType("a"), opts));
//clang-format on
}
TEST_CASE_FIXTURE(Fixture, "nil_or_nil_is_nil_not_question_mark")
{
CheckResult result = check(R"(
type nil_ty = nil | nil
local a : nil_ty = nil
)");
ToStringOptions opts;
opts.useLineBreaks = false;
CHECK_EQ("nil", toString(requireType("a"), opts));
}
TEST_CASE_FIXTURE(Fixture, "long_disjunct_of_nil_is_nil_not_question_mark")
{
CheckResult result = check(R"(
type nil_ty = nil | nil | nil | nil | nil
local a : nil_ty = nil
)");
ToStringOptions opts;
opts.useLineBreaks = false;
CHECK_EQ("nil", toString(requireType("a"), opts));
}
TEST_CASE_FIXTURE(Fixture, "metatable")
{
Type table{TypeVariant(TableType())};
Type metatable{TypeVariant(TableType())};
Type mtv{TypeVariant(MetatableType{&table, &metatable})};
if (FFlag::DebugLuauDeferredConstraintResolution)
CHECK_EQ("{ @metatable {| |}, {| |} }", toString(&mtv));
else
CHECK_EQ("{ @metatable { }, { } }", toString(&mtv));
}
TEST_CASE_FIXTURE(Fixture, "named_metatable")
{
Type table{TypeVariant(TableType())};
Type metatable{TypeVariant(TableType())};
Type mtv{TypeVariant(MetatableType{&table, &metatable, "NamedMetatable"})};
CHECK_EQ("NamedMetatable", toString(&mtv));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "named_metatable_toStringNamedFunction")
{
CheckResult result = check(R"(
local function createTbl(): NamedMetatable
return setmetatable({}, {})
end
type NamedMetatable = typeof(createTbl())
)");
TypeId ty = requireType("createTbl");
const FunctionType* ftv = get<FunctionType>(follow(ty));
REQUIRE(ftv);
CHECK_EQ("createTbl(): NamedMetatable", toStringNamedFunction("createTbl", *ftv));
}
2022-05-14 03:36:37 +08:00
TEST_CASE_FIXTURE(BuiltinsFixture, "exhaustive_toString_of_cyclic_table")
{
CheckResult result = check(R"(
--!strict
local Vec3 = {}
Vec3.__index = Vec3
function Vec3.new()
return setmetatable({x=0, y=0, z=0}, Vec3)
end
export type Vec3 = typeof(Vec3.new())
local thefun: any = function(self, o) return self end
local multiply: ((Vec3, Vec3) -> Vec3) & ((Vec3, number) -> Vec3) = thefun
Vec3.__mul = multiply
local a = Vec3.new()
)");
std::string a = toString(requireType("a"), {true});
CHECK_EQ(std::string::npos, a.find("CYCLE"));
CHECK_EQ(std::string::npos, a.find("TRUNCATED"));
//clang-format off
CHECK_EQ("t2 where "
"t1 = { __index: t1, __mul: ((t2, number) -> t2) & ((t2, t2) -> t2), new: () -> t2 } ; "
"t2 = { @metatable t1, {| x: number, y: number, z: number |} }",
a);
//clang-format on
}
TEST_CASE_FIXTURE(Fixture, "intersection_parenthesized_only_if_needed")
{
auto utv = Type{UnionType{{builtinTypes->numberType, builtinTypes->stringType}}};
auto itv = Type{IntersectionType{{&utv, builtinTypes->booleanType}}};
CHECK_EQ(toString(&itv), "(number | string) & boolean");
}
TEST_CASE_FIXTURE(Fixture, "union_parenthesized_only_if_needed")
{
auto itv = Type{IntersectionType{{builtinTypes->numberType, builtinTypes->stringType}}};
auto utv = Type{UnionType{{&itv, builtinTypes->booleanType}}};
CHECK_EQ(toString(&utv), "(number & string) | boolean");
}
TEST_CASE_FIXTURE(Fixture, "functions_are_always_parenthesized_in_unions_or_intersections")
{
auto stringAndNumberPack = TypePackVar{TypePack{{builtinTypes->stringType, builtinTypes->numberType}}};
auto numberAndStringPack = TypePackVar{TypePack{{builtinTypes->numberType, builtinTypes->stringType}}};
auto sn2ns = Type{FunctionType{&stringAndNumberPack, &numberAndStringPack}};
auto ns2sn = Type{FunctionType(frontend.globals.globalScope->level, &numberAndStringPack, &stringAndNumberPack)};
auto utv = Type{UnionType{{&ns2sn, &sn2ns}}};
auto itv = Type{IntersectionType{{&ns2sn, &sn2ns}}};
CHECK_EQ(toString(&utv), "((number, string) -> (string, number)) | ((string, number) -> (number, string))");
CHECK_EQ(toString(&itv), "((number, string) -> (string, number)) & ((string, number) -> (number, string))");
}
TEST_CASE_FIXTURE(Fixture, "simple_intersections_printed_on_one_line")
{
Sync to upstream/release/605 (#1118) - Implemented [Require by String with Relative Paths](https://github.com/luau-lang/rfcs/blob/master/docs/new-require-by-string-semantics.md) RFC - Implemented [Require by String with Aliases](https://github.com/luau-lang/rfcs/blob/master/docs/require-by-string-aliases.md) RFC with support for `paths` and `alias` arrays in .luarc - Added SUBRK and DIVRK bytecode instructions to speed up constant-number and constant/number operations - Added `--vector-lib`, `--vector-ctor` and `--vector-type` options to luau-compile to support code with vectors New Solver - Correctness fixes to subtyping - Improvements to dataflow analysis Native Code Generation - Added bytecode analysis pass to predict type tags used in operations - Fixed rare cases of numerical loops being generated without an interrupt instruction - Restored optimization data propagation into the linear block - Duplicate buffer length checks are optimized away Miscellaneous - Small performance improvements to new non-strict mode - Introduced more scripts for fuzzing Luau and processing the results, including fuzzer build support for CMake Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@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: 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: 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>
2023-12-02 15:46:57 +08:00
ScopedFastFlag sff{FFlag::LuauToStringSimpleCompositeTypesSingleLine, true};
CheckResult result = check(R"(
local a: string & number
)");
ToStringOptions opts;
opts.useLineBreaks = true;
CHECK_EQ("number & string", toString(requireType("a"), opts));
}
TEST_CASE_FIXTURE(Fixture, "complex_intersections_printed_on_multiple_lines")
{
Sync to upstream/release/605 (#1118) - Implemented [Require by String with Relative Paths](https://github.com/luau-lang/rfcs/blob/master/docs/new-require-by-string-semantics.md) RFC - Implemented [Require by String with Aliases](https://github.com/luau-lang/rfcs/blob/master/docs/require-by-string-aliases.md) RFC with support for `paths` and `alias` arrays in .luarc - Added SUBRK and DIVRK bytecode instructions to speed up constant-number and constant/number operations - Added `--vector-lib`, `--vector-ctor` and `--vector-type` options to luau-compile to support code with vectors New Solver - Correctness fixes to subtyping - Improvements to dataflow analysis Native Code Generation - Added bytecode analysis pass to predict type tags used in operations - Fixed rare cases of numerical loops being generated without an interrupt instruction - Restored optimization data propagation into the linear block - Duplicate buffer length checks are optimized away Miscellaneous - Small performance improvements to new non-strict mode - Introduced more scripts for fuzzing Luau and processing the results, including fuzzer build support for CMake Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@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: 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: 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>
2023-12-02 15:46:57 +08:00
ScopedFastFlag sff{FFlag::LuauToStringSimpleCompositeTypesSingleLine, true};
CheckResult result = check(R"(
local a: string & number & boolean
)");
ToStringOptions opts;
opts.useLineBreaks = true;
opts.compositeTypesSingleLineLimit = 2;
//clang-format off
CHECK_EQ("boolean\n"
"& number\n"
"& string",
toString(requireType("a"), opts));
//clang-format on
}
TEST_CASE_FIXTURE(Fixture, "overloaded_functions_always_printed_on_multiple_lines")
{
Sync to upstream/release/605 (#1118) - Implemented [Require by String with Relative Paths](https://github.com/luau-lang/rfcs/blob/master/docs/new-require-by-string-semantics.md) RFC - Implemented [Require by String with Aliases](https://github.com/luau-lang/rfcs/blob/master/docs/require-by-string-aliases.md) RFC with support for `paths` and `alias` arrays in .luarc - Added SUBRK and DIVRK bytecode instructions to speed up constant-number and constant/number operations - Added `--vector-lib`, `--vector-ctor` and `--vector-type` options to luau-compile to support code with vectors New Solver - Correctness fixes to subtyping - Improvements to dataflow analysis Native Code Generation - Added bytecode analysis pass to predict type tags used in operations - Fixed rare cases of numerical loops being generated without an interrupt instruction - Restored optimization data propagation into the linear block - Duplicate buffer length checks are optimized away Miscellaneous - Small performance improvements to new non-strict mode - Introduced more scripts for fuzzing Luau and processing the results, including fuzzer build support for CMake Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@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: 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: 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>
2023-12-02 15:46:57 +08:00
ScopedFastFlag sff{FFlag::LuauToStringSimpleCompositeTypesSingleLine, true};
CheckResult result = check(R"(
local a: ((string) -> string) & ((number) -> number)
)");
ToStringOptions opts;
opts.useLineBreaks = true;
//clang-format off
CHECK_EQ("((number) -> number)\n"
"& ((string) -> string)",
toString(requireType("a"), opts));
//clang-format on
}
TEST_CASE_FIXTURE(Fixture, "simple_unions_printed_on_one_line")
{
Sync to upstream/release/605 (#1118) - Implemented [Require by String with Relative Paths](https://github.com/luau-lang/rfcs/blob/master/docs/new-require-by-string-semantics.md) RFC - Implemented [Require by String with Aliases](https://github.com/luau-lang/rfcs/blob/master/docs/require-by-string-aliases.md) RFC with support for `paths` and `alias` arrays in .luarc - Added SUBRK and DIVRK bytecode instructions to speed up constant-number and constant/number operations - Added `--vector-lib`, `--vector-ctor` and `--vector-type` options to luau-compile to support code with vectors New Solver - Correctness fixes to subtyping - Improvements to dataflow analysis Native Code Generation - Added bytecode analysis pass to predict type tags used in operations - Fixed rare cases of numerical loops being generated without an interrupt instruction - Restored optimization data propagation into the linear block - Duplicate buffer length checks are optimized away Miscellaneous - Small performance improvements to new non-strict mode - Introduced more scripts for fuzzing Luau and processing the results, including fuzzer build support for CMake Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@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: 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: 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>
2023-12-02 15:46:57 +08:00
ScopedFastFlag sff{FFlag::LuauToStringSimpleCompositeTypesSingleLine, true};
CheckResult result = check(R"(
local a: number | boolean
)");
ToStringOptions opts;
opts.useLineBreaks = true;
CHECK_EQ("boolean | number", toString(requireType("a"), opts));
}
TEST_CASE_FIXTURE(Fixture, "complex_unions_printed_on_multiple_lines")
{
Sync to upstream/release/605 (#1118) - Implemented [Require by String with Relative Paths](https://github.com/luau-lang/rfcs/blob/master/docs/new-require-by-string-semantics.md) RFC - Implemented [Require by String with Aliases](https://github.com/luau-lang/rfcs/blob/master/docs/require-by-string-aliases.md) RFC with support for `paths` and `alias` arrays in .luarc - Added SUBRK and DIVRK bytecode instructions to speed up constant-number and constant/number operations - Added `--vector-lib`, `--vector-ctor` and `--vector-type` options to luau-compile to support code with vectors New Solver - Correctness fixes to subtyping - Improvements to dataflow analysis Native Code Generation - Added bytecode analysis pass to predict type tags used in operations - Fixed rare cases of numerical loops being generated without an interrupt instruction - Restored optimization data propagation into the linear block - Duplicate buffer length checks are optimized away Miscellaneous - Small performance improvements to new non-strict mode - Introduced more scripts for fuzzing Luau and processing the results, including fuzzer build support for CMake Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@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: 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: 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>
2023-12-02 15:46:57 +08:00
ScopedFastFlag sff{FFlag::LuauToStringSimpleCompositeTypesSingleLine, true};
CheckResult result = check(R"(
local a: string | number | boolean
)");
ToStringOptions opts;
opts.compositeTypesSingleLineLimit = 2;
opts.useLineBreaks = true;
//clang-format off
CHECK_EQ("boolean\n"
"| number\n"
"| string",
toString(requireType("a"), opts));
//clang-format on
}
TEST_CASE_FIXTURE(Fixture, "quit_stringifying_table_type_when_length_is_exceeded")
{
TableType ttv{};
for (char c : std::string("abcdefghijklmno"))
ttv.props[std::string(1, c)] = {builtinTypes->numberType};
Type tv{ttv};
ToStringOptions o;
o.exhaustive = false;
o.maxTableLength = 40;
if (FFlag::DebugLuauDeferredConstraintResolution)
CHECK_EQ(toString(&tv, o), "{| a: number, b: number, c: number, d: number, e: number, ... 10 more ... |}");
else
CHECK_EQ(toString(&tv, o), "{ a: number, b: number, c: number, d: number, e: number, ... 10 more ... }");
}
TEST_CASE_FIXTURE(Fixture, "stringifying_table_type_is_still_capped_when_exhaustive")
{
TableType ttv{};
for (char c : std::string("abcdefg"))
ttv.props[std::string(1, c)] = {builtinTypes->numberType};
Type tv{ttv};
ToStringOptions o;
o.exhaustive = true;
o.maxTableLength = 40;
if (FFlag::DebugLuauDeferredConstraintResolution)
CHECK_EQ(toString(&tv, o), "{| a: number, b: number, c: number, d: number, e: number, ... 2 more ... |}");
else
CHECK_EQ(toString(&tv, o), "{ a: number, b: number, c: number, d: number, e: number, ... 2 more ... }");
}
TEST_CASE_FIXTURE(Fixture, "quit_stringifying_type_when_length_is_exceeded")
{
CheckResult result = check(R"(
function f0() end
function f1(f) return f or f0 end
function f2(f) return f or f1 end
function f3(f) return f or f2 end
)");
LUAU_REQUIRE_NO_ERRORS(result);
ToStringOptions o;
o.exhaustive = false;
if (FFlag::DebugLuauDeferredConstraintResolution)
{
o.maxTypeLength = 30;
CHECK_EQ(toString(requireType("f0"), o), "() -> ()");
Sync to upstream/release/577 (#934) Lots of things going on this week: * Fix a crash that could occur in the presence of a cyclic union. We shouldn't be creating cyclic unions, but we shouldn't be crashing when they arise either. * Minor cleanup of `luau_precall` * Internal change to make L->top handling slightly more uniform * Optimize SETGLOBAL & GETGLOBAL fallback C functions. * https://github.com/Roblox/luau/pull/929 * The syntax to the `luau-reduce` commandline tool has changed. It now accepts a script, a command to execute, and an error to search for. It no longer automatically passes the script to the command which makes it a lot more flexible. Also be warned that it edits the script it is passed **in place**. Do not point it at something that is not in source control! New solver * Switch to a greedier but more fallible algorithm for simplifying union and intersection types that are created as part of refinement calculation. This has much better and more predictable performance. * Fix a constraint cycle in recursive function calls. * Much improved inference of binary addition. Functions like `function add(x, y) return x + y end` can now be inferred without annotations. We also accurately typecheck calls to functions like this. * Many small bugfixes surrounding things like table indexers * Add support for indexers on class types. This was previously added to the old solver; we now add it to the new one for feature parity. JIT * https://github.com/Roblox/luau/pull/931 * Fuse key.value and key.tt loads for CEHCK_SLOT_MATCH in A64 * Implement remaining aliases of BFM for A64 * Implement new callinfo flag for A64 * Add instruction simplification for int->num->int conversion chains * Don't even load execdata for X64 calls * Treat opcode fallbacks the same as manually written fallbacks --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2023-05-20 03:37:30 +08:00
CHECK_EQ(toString(requireType("f1"), o), "<a>(a) -> (() -> ()) | (a & ~(false?))... *TRUNCATED*");
CHECK_EQ(toString(requireType("f2"), o), "<b>(b) -> (<a>(a) -> (() -> ()) | (a & ~(false?))... *TRUNCATED*");
CHECK_EQ(toString(requireType("f3"), o), "<c>(c) -> (<b>(b) -> (<a>(a) -> (() -> ()) | (a & ~(false?))... *TRUNCATED*");
}
else
{
o.maxTypeLength = 40;
CHECK_EQ(toString(requireType("f0"), o), "() -> ()");
CHECK_EQ(toString(requireType("f1"), o), "(() -> ()) -> () -> ()");
CHECK_EQ(toString(requireType("f2"), o), "((() -> ()) -> () -> ()) -> (() -> ()) -> ... *TRUNCATED*");
CHECK_EQ(toString(requireType("f3"), o), "(((() -> ()) -> () -> ()) -> (() -> ()) -> ... *TRUNCATED*");
}
}
TEST_CASE_FIXTURE(Fixture, "stringifying_type_is_still_capped_when_exhaustive")
{
CheckResult result = check(R"(
function f0() end
function f1(f) return f or f0 end
function f2(f) return f or f1 end
function f3(f) return f or f2 end
)");
LUAU_REQUIRE_NO_ERRORS(result);
ToStringOptions o;
o.exhaustive = true;
if (FFlag::DebugLuauDeferredConstraintResolution)
{
o.maxTypeLength = 30;
CHECK_EQ(toString(requireType("f0"), o), "() -> ()");
Sync to upstream/release/577 (#934) Lots of things going on this week: * Fix a crash that could occur in the presence of a cyclic union. We shouldn't be creating cyclic unions, but we shouldn't be crashing when they arise either. * Minor cleanup of `luau_precall` * Internal change to make L->top handling slightly more uniform * Optimize SETGLOBAL & GETGLOBAL fallback C functions. * https://github.com/Roblox/luau/pull/929 * The syntax to the `luau-reduce` commandline tool has changed. It now accepts a script, a command to execute, and an error to search for. It no longer automatically passes the script to the command which makes it a lot more flexible. Also be warned that it edits the script it is passed **in place**. Do not point it at something that is not in source control! New solver * Switch to a greedier but more fallible algorithm for simplifying union and intersection types that are created as part of refinement calculation. This has much better and more predictable performance. * Fix a constraint cycle in recursive function calls. * Much improved inference of binary addition. Functions like `function add(x, y) return x + y end` can now be inferred without annotations. We also accurately typecheck calls to functions like this. * Many small bugfixes surrounding things like table indexers * Add support for indexers on class types. This was previously added to the old solver; we now add it to the new one for feature parity. JIT * https://github.com/Roblox/luau/pull/931 * Fuse key.value and key.tt loads for CEHCK_SLOT_MATCH in A64 * Implement remaining aliases of BFM for A64 * Implement new callinfo flag for A64 * Add instruction simplification for int->num->int conversion chains * Don't even load execdata for X64 calls * Treat opcode fallbacks the same as manually written fallbacks --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2023-05-20 03:37:30 +08:00
CHECK_EQ(toString(requireType("f1"), o), "<a>(a) -> (() -> ()) | (a & ~(false?))... *TRUNCATED*");
CHECK_EQ(toString(requireType("f2"), o), "<b>(b) -> (<a>(a) -> (() -> ()) | (a & ~(false?))... *TRUNCATED*");
CHECK_EQ(toString(requireType("f3"), o), "<c>(c) -> (<b>(b) -> (<a>(a) -> (() -> ()) | (a & ~(false?))... *TRUNCATED*");
}
else
{
o.maxTypeLength = 40;
CHECK_EQ(toString(requireType("f0"), o), "() -> ()");
CHECK_EQ(toString(requireType("f1"), o), "(() -> ()) -> () -> ()");
CHECK_EQ(toString(requireType("f2"), o), "((() -> ()) -> () -> ()) -> (() -> ()) -> ... *TRUNCATED*");
CHECK_EQ(toString(requireType("f3"), o), "(((() -> ()) -> () -> ()) -> (() -> ()) -> ... *TRUNCATED*");
}
}
TEST_CASE_FIXTURE(Fixture, "stringifying_table_type_correctly_use_matching_table_state_braces")
{
TableType ttv{TableState::Sealed, TypeLevel{}};
for (char c : std::string("abcdefghij"))
ttv.props[std::string(1, c)] = {builtinTypes->numberType};
Type tv{ttv};
ToStringOptions o;
o.maxTableLength = 40;
if (FFlag::DebugLuauDeferredConstraintResolution)
CHECK_EQ(toString(&tv, o), "{ a: number, b: number, c: number, d: number, e: number, ... 5 more ... }");
else
CHECK_EQ(toString(&tv, o), "{| a: number, b: number, c: number, d: number, e: number, ... 5 more ... |}");
}
TEST_CASE_FIXTURE(Fixture, "stringifying_cyclic_union_type_bails_early")
{
Type tv{UnionType{{builtinTypes->stringType, builtinTypes->numberType}}};
UnionType* utv = getMutable<UnionType>(&tv);
utv->options.push_back(&tv);
utv->options.push_back(&tv);
CHECK_EQ("t1 where t1 = number | string", toString(&tv));
}
TEST_CASE_FIXTURE(Fixture, "stringifying_cyclic_intersection_type_bails_early")
{
Type tv{IntersectionType{}};
IntersectionType* itv = getMutable<IntersectionType>(&tv);
itv->parts.push_back(&tv);
itv->parts.push_back(&tv);
CHECK_EQ("t1 where t1 = t1 & t1", toString(&tv));
}
TEST_CASE_FIXTURE(Fixture, "stringifying_array_uses_array_syntax")
{
TableType ttv{TableState::Sealed, TypeLevel{}};
ttv.indexer = TableIndexer{builtinTypes->numberType, builtinTypes->stringType};
CHECK_EQ("{string}", toString(Type{ttv}));
ttv.props["A"] = {builtinTypes->numberType};
if (FFlag::DebugLuauDeferredConstraintResolution)
CHECK_EQ("{ [number]: string, A: number }", toString(Type{ttv}));
else
CHECK_EQ("{| [number]: string, A: number |}", toString(Type{ttv}));
ttv.props.clear();
ttv.state = TableState::Unsealed;
CHECK_EQ("{string}", toString(Type{ttv}));
}
TEST_CASE_FIXTURE(Fixture, "generic_packs_are_stringified_differently_from_generic_types")
{
TypePackVar tpv{GenericTypePack{"a"}};
CHECK_EQ(toString(&tpv), "a...");
Type tv{GenericType{"a"}};
CHECK_EQ(toString(&tv), "a");
}
TEST_CASE_FIXTURE(Fixture, "function_type_with_argument_names")
{
CheckResult result = check("type MyFunc = (a: number, string, c: number) -> string; local a : MyFunc");
LUAU_REQUIRE_NO_ERRORS(result);
ToStringOptions opts;
opts.functionTypeArguments = true;
CHECK_EQ("(a: number, string, c: number) -> string", toString(requireType("a"), opts));
}
TEST_CASE_FIXTURE(Fixture, "function_type_with_argument_names_generic")
{
CheckResult result = check("local function f<a...>(n: number, ...: a...): (a...) return ... end");
LUAU_REQUIRE_NO_ERRORS(result);
ToStringOptions opts;
opts.functionTypeArguments = true;
CHECK_EQ("<a...>(n: number, a...) -> (a...)", toString(requireType("f"), opts));
}
TEST_CASE_FIXTURE(Fixture, "function_type_with_argument_names_and_self")
{
CheckResult result = check(R"(
local tbl = {}
tbl.a = 2
function tbl:foo(b: number, c: number) return (self.a :: number) + b + c end
type Table = typeof(tbl)
type Foo = typeof(tbl.foo)
local u: Foo
)");
LUAU_REQUIRE_NO_ERRORS(result);
ToStringOptions opts;
opts.functionTypeArguments = true;
// Can't guess the name of 'self' to compare name, but at least there should be no assertion
toString(requireType("u"), opts);
}
TEST_CASE_FIXTURE(Fixture, "generate_friendly_names_for_inferred_generics")
{
CheckResult result = check(R"(
function id(x) return x end
function id2(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30)
return a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ("<a>(a) -> a", toString(requireType("id")));
CHECK_EQ("<a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1>(a, b, c, d, e, f, g, h, i, j, k, l, "
"m, n, o, p, q, r, s, t, u, v, w, x, y, z, a1, b1, c1, d1) -> (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, "
"x, y, z, a1, b1, c1, d1)",
toString(requireType("id2")));
}
TEST_CASE_FIXTURE(Fixture, "toStringDetailed")
{
CheckResult result = check(R"(
function id3(a, b, c)
return a, b, c
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
ToStringOptions opts;
TypeId id3Type = requireType("id3");
ToStringResult nameData = toStringDetailed(id3Type, opts);
REQUIRE(3 == opts.nameMap.types.size());
REQUIRE_EQ("<a, b, c>(a, b, c) -> (a, b, c)", nameData.name);
const FunctionType* ftv = get<FunctionType>(follow(id3Type));
REQUIRE(ftv != nullptr);
auto params = flatten(ftv->argTypes).first;
REQUIRE(3 == params.size());
CHECK("a" == toString(params[0], opts));
CHECK("b" == toString(params[1], opts));
CHECK("c" == toString(params[2], opts));
}
2022-05-14 03:36:37 +08:00
TEST_CASE_FIXTURE(BuiltinsFixture, "toStringDetailed2")
{
ScopedFastFlag sff[] = {
Sync to upstream/release/605 (#1118) - Implemented [Require by String with Relative Paths](https://github.com/luau-lang/rfcs/blob/master/docs/new-require-by-string-semantics.md) RFC - Implemented [Require by String with Aliases](https://github.com/luau-lang/rfcs/blob/master/docs/require-by-string-aliases.md) RFC with support for `paths` and `alias` arrays in .luarc - Added SUBRK and DIVRK bytecode instructions to speed up constant-number and constant/number operations - Added `--vector-lib`, `--vector-ctor` and `--vector-type` options to luau-compile to support code with vectors New Solver - Correctness fixes to subtyping - Improvements to dataflow analysis Native Code Generation - Added bytecode analysis pass to predict type tags used in operations - Fixed rare cases of numerical loops being generated without an interrupt instruction - Restored optimization data propagation into the linear block - Duplicate buffer length checks are optimized away Miscellaneous - Small performance improvements to new non-strict mode - Introduced more scripts for fuzzing Luau and processing the results, including fuzzer build support for CMake Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@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: 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: 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>
2023-12-02 15:46:57 +08:00
{FFlag::DebugLuauSharedSelf, true},
};
2022-07-01 07:52:43 +08:00
CheckResult result = check(R"(
local base = {}
function base:one() return 1 end
local child = {}
setmetatable(child, {__index=base})
function child:two() return 2 end
local inst = {}
setmetatable(inst, {__index=child})
)");
LUAU_REQUIRE_NO_ERRORS(result);
ToStringOptions opts;
TypeId tType = requireType("inst");
ToStringResult r = toStringDetailed(tType, opts);
2022-07-01 07:52:43 +08:00
CHECK_EQ("{ @metatable { __index: { @metatable {| __index: base |}, child } }, inst }", r.name);
CHECK(0 == opts.nameMap.types.size());
Sync to upstream/release/577 (#934) Lots of things going on this week: * Fix a crash that could occur in the presence of a cyclic union. We shouldn't be creating cyclic unions, but we shouldn't be crashing when they arise either. * Minor cleanup of `luau_precall` * Internal change to make L->top handling slightly more uniform * Optimize SETGLOBAL & GETGLOBAL fallback C functions. * https://github.com/Roblox/luau/pull/929 * The syntax to the `luau-reduce` commandline tool has changed. It now accepts a script, a command to execute, and an error to search for. It no longer automatically passes the script to the command which makes it a lot more flexible. Also be warned that it edits the script it is passed **in place**. Do not point it at something that is not in source control! New solver * Switch to a greedier but more fallible algorithm for simplifying union and intersection types that are created as part of refinement calculation. This has much better and more predictable performance. * Fix a constraint cycle in recursive function calls. * Much improved inference of binary addition. Functions like `function add(x, y) return x + y end` can now be inferred without annotations. We also accurately typecheck calls to functions like this. * Many small bugfixes surrounding things like table indexers * Add support for indexers on class types. This was previously added to the old solver; we now add it to the new one for feature parity. JIT * https://github.com/Roblox/luau/pull/931 * Fuse key.value and key.tt loads for CEHCK_SLOT_MATCH in A64 * Implement remaining aliases of BFM for A64 * Implement new callinfo flag for A64 * Add instruction simplification for int->num->int conversion chains * Don't even load execdata for X64 calls * Treat opcode fallbacks the same as manually written fallbacks --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2023-05-20 03:37:30 +08:00
const MetatableType* tMeta = get<MetatableType>(follow(tType));
REQUIRE(tMeta);
Sync to upstream/release/577 (#934) Lots of things going on this week: * Fix a crash that could occur in the presence of a cyclic union. We shouldn't be creating cyclic unions, but we shouldn't be crashing when they arise either. * Minor cleanup of `luau_precall` * Internal change to make L->top handling slightly more uniform * Optimize SETGLOBAL & GETGLOBAL fallback C functions. * https://github.com/Roblox/luau/pull/929 * The syntax to the `luau-reduce` commandline tool has changed. It now accepts a script, a command to execute, and an error to search for. It no longer automatically passes the script to the command which makes it a lot more flexible. Also be warned that it edits the script it is passed **in place**. Do not point it at something that is not in source control! New solver * Switch to a greedier but more fallible algorithm for simplifying union and intersection types that are created as part of refinement calculation. This has much better and more predictable performance. * Fix a constraint cycle in recursive function calls. * Much improved inference of binary addition. Functions like `function add(x, y) return x + y end` can now be inferred without annotations. We also accurately typecheck calls to functions like this. * Many small bugfixes surrounding things like table indexers * Add support for indexers on class types. This was previously added to the old solver; we now add it to the new one for feature parity. JIT * https://github.com/Roblox/luau/pull/931 * Fuse key.value and key.tt loads for CEHCK_SLOT_MATCH in A64 * Implement remaining aliases of BFM for A64 * Implement new callinfo flag for A64 * Add instruction simplification for int->num->int conversion chains * Don't even load execdata for X64 calls * Treat opcode fallbacks the same as manually written fallbacks --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2023-05-20 03:37:30 +08:00
TableType* tMeta2 = getMutable<TableType>(follow(tMeta->metatable));
REQUIRE(tMeta2);
REQUIRE(tMeta2->props.count("__index"));
Sync to upstream/release/577 (#934) Lots of things going on this week: * Fix a crash that could occur in the presence of a cyclic union. We shouldn't be creating cyclic unions, but we shouldn't be crashing when they arise either. * Minor cleanup of `luau_precall` * Internal change to make L->top handling slightly more uniform * Optimize SETGLOBAL & GETGLOBAL fallback C functions. * https://github.com/Roblox/luau/pull/929 * The syntax to the `luau-reduce` commandline tool has changed. It now accepts a script, a command to execute, and an error to search for. It no longer automatically passes the script to the command which makes it a lot more flexible. Also be warned that it edits the script it is passed **in place**. Do not point it at something that is not in source control! New solver * Switch to a greedier but more fallible algorithm for simplifying union and intersection types that are created as part of refinement calculation. This has much better and more predictable performance. * Fix a constraint cycle in recursive function calls. * Much improved inference of binary addition. Functions like `function add(x, y) return x + y end` can now be inferred without annotations. We also accurately typecheck calls to functions like this. * Many small bugfixes surrounding things like table indexers * Add support for indexers on class types. This was previously added to the old solver; we now add it to the new one for feature parity. JIT * https://github.com/Roblox/luau/pull/931 * Fuse key.value and key.tt loads for CEHCK_SLOT_MATCH in A64 * Implement remaining aliases of BFM for A64 * Implement new callinfo flag for A64 * Add instruction simplification for int->num->int conversion chains * Don't even load execdata for X64 calls * Treat opcode fallbacks the same as manually written fallbacks --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2023-05-20 03:37:30 +08:00
const MetatableType* tMeta3 = get<MetatableType>(follow(tMeta2->props["__index"].type()));
REQUIRE(tMeta3);
Sync to upstream/release/577 (#934) Lots of things going on this week: * Fix a crash that could occur in the presence of a cyclic union. We shouldn't be creating cyclic unions, but we shouldn't be crashing when they arise either. * Minor cleanup of `luau_precall` * Internal change to make L->top handling slightly more uniform * Optimize SETGLOBAL & GETGLOBAL fallback C functions. * https://github.com/Roblox/luau/pull/929 * The syntax to the `luau-reduce` commandline tool has changed. It now accepts a script, a command to execute, and an error to search for. It no longer automatically passes the script to the command which makes it a lot more flexible. Also be warned that it edits the script it is passed **in place**. Do not point it at something that is not in source control! New solver * Switch to a greedier but more fallible algorithm for simplifying union and intersection types that are created as part of refinement calculation. This has much better and more predictable performance. * Fix a constraint cycle in recursive function calls. * Much improved inference of binary addition. Functions like `function add(x, y) return x + y end` can now be inferred without annotations. We also accurately typecheck calls to functions like this. * Many small bugfixes surrounding things like table indexers * Add support for indexers on class types. This was previously added to the old solver; we now add it to the new one for feature parity. JIT * https://github.com/Roblox/luau/pull/931 * Fuse key.value and key.tt loads for CEHCK_SLOT_MATCH in A64 * Implement remaining aliases of BFM for A64 * Implement new callinfo flag for A64 * Add instruction simplification for int->num->int conversion chains * Don't even load execdata for X64 calls * Treat opcode fallbacks the same as manually written fallbacks --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2023-05-20 03:37:30 +08:00
TableType* tMeta4 = getMutable<TableType>(follow(tMeta3->metatable));
REQUIRE(tMeta4);
REQUIRE(tMeta4->props.count("__index"));
Sync to upstream/release/577 (#934) Lots of things going on this week: * Fix a crash that could occur in the presence of a cyclic union. We shouldn't be creating cyclic unions, but we shouldn't be crashing when they arise either. * Minor cleanup of `luau_precall` * Internal change to make L->top handling slightly more uniform * Optimize SETGLOBAL & GETGLOBAL fallback C functions. * https://github.com/Roblox/luau/pull/929 * The syntax to the `luau-reduce` commandline tool has changed. It now accepts a script, a command to execute, and an error to search for. It no longer automatically passes the script to the command which makes it a lot more flexible. Also be warned that it edits the script it is passed **in place**. Do not point it at something that is not in source control! New solver * Switch to a greedier but more fallible algorithm for simplifying union and intersection types that are created as part of refinement calculation. This has much better and more predictable performance. * Fix a constraint cycle in recursive function calls. * Much improved inference of binary addition. Functions like `function add(x, y) return x + y end` can now be inferred without annotations. We also accurately typecheck calls to functions like this. * Many small bugfixes surrounding things like table indexers * Add support for indexers on class types. This was previously added to the old solver; we now add it to the new one for feature parity. JIT * https://github.com/Roblox/luau/pull/931 * Fuse key.value and key.tt loads for CEHCK_SLOT_MATCH in A64 * Implement remaining aliases of BFM for A64 * Implement new callinfo flag for A64 * Add instruction simplification for int->num->int conversion chains * Don't even load execdata for X64 calls * Treat opcode fallbacks the same as manually written fallbacks --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2023-05-20 03:37:30 +08:00
TableType* tMeta5 = getMutable<TableType>(follow(tMeta4->props["__index"].type()));
REQUIRE(tMeta5);
REQUIRE(tMeta5->props.count("one") > 0);
Sync to upstream/release/577 (#934) Lots of things going on this week: * Fix a crash that could occur in the presence of a cyclic union. We shouldn't be creating cyclic unions, but we shouldn't be crashing when they arise either. * Minor cleanup of `luau_precall` * Internal change to make L->top handling slightly more uniform * Optimize SETGLOBAL & GETGLOBAL fallback C functions. * https://github.com/Roblox/luau/pull/929 * The syntax to the `luau-reduce` commandline tool has changed. It now accepts a script, a command to execute, and an error to search for. It no longer automatically passes the script to the command which makes it a lot more flexible. Also be warned that it edits the script it is passed **in place**. Do not point it at something that is not in source control! New solver * Switch to a greedier but more fallible algorithm for simplifying union and intersection types that are created as part of refinement calculation. This has much better and more predictable performance. * Fix a constraint cycle in recursive function calls. * Much improved inference of binary addition. Functions like `function add(x, y) return x + y end` can now be inferred without annotations. We also accurately typecheck calls to functions like this. * Many small bugfixes surrounding things like table indexers * Add support for indexers on class types. This was previously added to the old solver; we now add it to the new one for feature parity. JIT * https://github.com/Roblox/luau/pull/931 * Fuse key.value and key.tt loads for CEHCK_SLOT_MATCH in A64 * Implement remaining aliases of BFM for A64 * Implement new callinfo flag for A64 * Add instruction simplification for int->num->int conversion chains * Don't even load execdata for X64 calls * Treat opcode fallbacks the same as manually written fallbacks --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2023-05-20 03:37:30 +08:00
TableType* tMeta6 = getMutable<TableType>(follow(tMeta3->table));
REQUIRE(tMeta6);
REQUIRE(tMeta6->props.count("two") > 0);
ToStringResult oneResult = toStringDetailed(tMeta5->props["one"].type(), opts);
std::string twoResult = toString(tMeta6->props["two"].type(), opts);
2022-07-01 07:52:43 +08:00
CHECK_EQ("<a>(a) -> number", oneResult.name);
CHECK_EQ("<b>(b) -> number", twoResult);
}
TEST_CASE_FIXTURE(Fixture, "toStringErrorPack")
{
CheckResult result = check(R"(
local function target(callback: nil) return callback(4, "hello") end
)");
LUAU_REQUIRE_ERRORS(result);
CHECK_EQ("(nil) -> (*error-type*)", toString(requireType("target")));
}
TEST_CASE_FIXTURE(Fixture, "toStringGenericPack")
{
CheckResult result = check(R"(
function foo(a, b) return a(b) end
)");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("foo")), "<a, b...>((a) -> (b...), a) -> (b...)");
}
TEST_CASE_FIXTURE(Fixture, "toString_the_boundTo_table_type_contained_within_a_TypePack")
{
Type tv1{TableType{}};
TableType* ttv = getMutable<TableType>(&tv1);
ttv->state = TableState::Sealed;
ttv->props["hello"] = {builtinTypes->numberType};
ttv->props["world"] = {builtinTypes->numberType};
TypePackVar tpv1{TypePack{{&tv1}}};
Type tv2{TableType{}};
TableType* bttv = getMutable<TableType>(&tv2);
bttv->state = TableState::Free;
bttv->props["hello"] = {builtinTypes->numberType};
bttv->boundTo = &tv1;
TypePackVar tpv2{TypePack{{&tv2}}};
if (FFlag::DebugLuauDeferredConstraintResolution)
{
CHECK_EQ("{ hello: number, world: number }", toString(&tpv1));
CHECK_EQ("{ hello: number, world: number }", toString(&tpv2));
}
else
{
CHECK_EQ("{| hello: number, world: number |}", toString(&tpv1));
CHECK_EQ("{| hello: number, world: number |}", toString(&tpv2));
}
}
TEST_CASE_FIXTURE(Fixture, "no_parentheses_around_return_type_if_pack_has_an_empty_head_link")
{
TypeArena arena;
TypePackId realTail = arena.addTypePack({builtinTypes->stringType});
TypePackId emptyTail = arena.addTypePack({}, realTail);
TypePackId argList = arena.addTypePack({builtinTypes->stringType});
TypeId functionType = arena.addType(FunctionType{argList, emptyTail});
CHECK("(string) -> string" == toString(functionType));
}
TEST_CASE_FIXTURE(Fixture, "no_parentheses_around_cyclic_function_type_in_union")
{
CheckResult result = check(R"(
type F = ((() -> number)?) -> F?
local function f(p) return f end
local g: F = f
)");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ("t1 where t1 = ((() -> number)?) -> t1?", toString(requireType("g")));
}
TEST_CASE_FIXTURE(Fixture, "no_parentheses_around_cyclic_function_type_in_intersection")
{
CheckResult result = check(R"(
function f() return f end
local a: ((number) -> ()) & typeof(f)
)");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ("((number) -> ()) & t1 where t1 = () -> t1", toString(requireType("a")));
}
TEST_CASE_FIXTURE(Fixture, "self_recursive_instantiated_param")
{
Type tableTy{TableType{}};
TableType* ttv = getMutable<TableType>(&tableTy);
ttv->name = "Table";
ttv->instantiatedTypeParams.push_back(&tableTy);
CHECK_EQ(toString(tableTy), "Table<Table>");
}
TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_id")
{
CheckResult result = check(R"(
local function id(x) return x end
)");
TypeId ty = requireType("id");
const FunctionType* ftv = get<FunctionType>(follow(ty));
CHECK_EQ("id<a>(x: a): a", toStringNamedFunction("id", *ftv));
}
TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_map")
{
CheckResult result = check(R"(
local function map(arr, fn)
local t = {}
for i = 0, #arr do
t[i] = fn(arr[i])
end
return t
end
)");
TypeId ty = requireType("map");
const FunctionType* ftv = get<FunctionType>(follow(ty));
CHECK_EQ("map<a, b>(arr: {a}, fn: (a) -> b): {b}", toStringNamedFunction("map", *ftv));
}
2022-01-15 00:20:09 +08:00
TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_generic_pack")
{
CheckResult result = check(R"(
local function f(a: number, b: string) end
local function test<T..., U...>(...: T...): U...
f(...)
return 1, 2, 3
end
)");
TypeId ty = requireType("test");
const FunctionType* ftv = get<FunctionType>(follow(ty));
2022-01-15 00:20:09 +08:00
CHECK_EQ("test<T..., U...>(...: T...): U...", toStringNamedFunction("test", *ftv));
}
TEST_CASE("toStringNamedFunction_unit_f")
{
TypePackVar empty{TypePack{}};
FunctionType ftv{&empty, &empty, {}, false};
CHECK_EQ("f(): ()", toStringNamedFunction("f", ftv));
}
TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_variadics")
{
CheckResult result = check(R"(
local function f<a, b...>(x: a, ...): (a, a, b...)
return x, x, ...
end
)");
TypeId ty = requireType("f");
auto ftv = get<FunctionType>(follow(ty));
CHECK_EQ("f<a, b...>(x: a, ...: any): (a, a, b...)", toStringNamedFunction("f", *ftv));
}
TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_variadics2")
{
CheckResult result = check(R"(
local function f(): ...number
return 1, 2, 3
end
)");
TypeId ty = requireType("f");
auto ftv = get<FunctionType>(follow(ty));
CHECK_EQ("f(): ...number", toStringNamedFunction("f", *ftv));
}
TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_variadics3")
{
CheckResult result = check(R"(
local function f(): (string, ...number)
return 'a', 1, 2, 3
end
)");
TypeId ty = requireType("f");
auto ftv = get<FunctionType>(follow(ty));
CHECK_EQ("f(): (string, ...number)", toStringNamedFunction("f", *ftv));
}
TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_type_annotation_has_partial_argnames")
{
CheckResult result = check(R"(
local f: (number, y: number) -> number
)");
TypeId ty = requireType("f");
auto ftv = get<FunctionType>(follow(ty));
CHECK_EQ("f(_: number, y: number): number", toStringNamedFunction("f", *ftv));
}
TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_hide_type_params")
{
CheckResult result = check(R"(
local function f<T>(x: T, g: <U>(T) -> U)): ()
end
)");
TypeId ty = requireType("f");
auto ftv = get<FunctionType>(follow(ty));
ToStringOptions opts;
opts.hideNamedFunctionTypeParameters = true;
CHECK_EQ("f(x: T, g: <U>(T) -> U): ()", toStringNamedFunction("f", *ftv, opts));
}
2022-03-25 06:04:14 +08:00
TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_overrides_param_names")
{
CheckResult result = check(R"(
local function test(a, b : string, ... : number) return a end
)");
TypeId ty = requireType("test");
const FunctionType* ftv = get<FunctionType>(follow(ty));
2022-03-25 06:04:14 +08:00
ToStringOptions opts;
opts.namedFunctionOverrideArgNames = {"first", "second", "third"};
CHECK_EQ("test<a>(first: a, second: string, ...: number): a", toStringNamedFunction("test", *ftv, opts));
}
2022-05-20 08:02:24 +08:00
TEST_CASE_FIXTURE(Fixture, "pick_distinct_names_for_mixed_explicit_and_implicit_generics")
{
CheckResult result = check(R"(
function foo<a>(x: a, y) end
)");
CHECK("<a, b>(a, b) -> ()" == toString(requireType("foo")));
}
TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_include_self_param")
{
2022-07-01 07:52:43 +08:00
ScopedFastFlag sff[]{
Sync to upstream/release/605 (#1118) - Implemented [Require by String with Relative Paths](https://github.com/luau-lang/rfcs/blob/master/docs/new-require-by-string-semantics.md) RFC - Implemented [Require by String with Aliases](https://github.com/luau-lang/rfcs/blob/master/docs/require-by-string-aliases.md) RFC with support for `paths` and `alias` arrays in .luarc - Added SUBRK and DIVRK bytecode instructions to speed up constant-number and constant/number operations - Added `--vector-lib`, `--vector-ctor` and `--vector-type` options to luau-compile to support code with vectors New Solver - Correctness fixes to subtyping - Improvements to dataflow analysis Native Code Generation - Added bytecode analysis pass to predict type tags used in operations - Fixed rare cases of numerical loops being generated without an interrupt instruction - Restored optimization data propagation into the linear block - Duplicate buffer length checks are optimized away Miscellaneous - Small performance improvements to new non-strict mode - Introduced more scripts for fuzzing Luau and processing the results, including fuzzer build support for CMake Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@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: 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: 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>
2023-12-02 15:46:57 +08:00
{FFlag::DebugLuauSharedSelf, true},
2022-07-01 07:52:43 +08:00
};
CheckResult result = check(R"(
local foo = {}
function foo:method(arg: string): ()
end
)");
TypeId parentTy = requireType("foo");
auto ttv = get<TableType>(follow(parentTy));
REQUIRE(ttv);
TypeId methodTy = ttv->props.at("method").type();
auto ftv = get<FunctionType>(follow(methodTy));
REQUIRE_MESSAGE(ftv, methodTy);
if (FFlag::DebugLuauDeferredConstraintResolution)
CHECK_EQ("foo:method(self: unknown, arg: string): ()", toStringNamedFunction("foo:method", *ftv));
else
CHECK_EQ("foo:method<a>(self: a, arg: string): ()", toStringNamedFunction("foo:method", *ftv));
}
TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_hide_self_param")
{
2022-07-01 07:52:43 +08:00
ScopedFastFlag sff[]{
Sync to upstream/release/605 (#1118) - Implemented [Require by String with Relative Paths](https://github.com/luau-lang/rfcs/blob/master/docs/new-require-by-string-semantics.md) RFC - Implemented [Require by String with Aliases](https://github.com/luau-lang/rfcs/blob/master/docs/require-by-string-aliases.md) RFC with support for `paths` and `alias` arrays in .luarc - Added SUBRK and DIVRK bytecode instructions to speed up constant-number and constant/number operations - Added `--vector-lib`, `--vector-ctor` and `--vector-type` options to luau-compile to support code with vectors New Solver - Correctness fixes to subtyping - Improvements to dataflow analysis Native Code Generation - Added bytecode analysis pass to predict type tags used in operations - Fixed rare cases of numerical loops being generated without an interrupt instruction - Restored optimization data propagation into the linear block - Duplicate buffer length checks are optimized away Miscellaneous - Small performance improvements to new non-strict mode - Introduced more scripts for fuzzing Luau and processing the results, including fuzzer build support for CMake Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@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: 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: 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>
2023-12-02 15:46:57 +08:00
{FFlag::DebugLuauSharedSelf, true},
2022-07-01 07:52:43 +08:00
};
CheckResult result = check(R"(
local foo = {}
function foo:method(arg: string): ()
end
)");
ToStringOptions opts;
opts.hideFunctionSelfArgument = true;
TypeId parentTy = requireType("foo");
auto ttv = get<TableType>(follow(parentTy));
REQUIRE_MESSAGE(ttv, "Expected a table but got " << toString(parentTy, opts));
TypeId methodTy = follow(ttv->props.at("method").type());
auto ftv = get<FunctionType>(methodTy);
REQUIRE_MESSAGE(ftv, "Expected a function but got " << toString(methodTy, opts));
if (FFlag::DebugLuauDeferredConstraintResolution)
CHECK_EQ("foo:method(arg: string): ()", toStringNamedFunction("foo:method", *ftv, opts));
else
CHECK_EQ("foo:method<a>(arg: string): ()", toStringNamedFunction("foo:method", *ftv, opts));
}
TEST_CASE_FIXTURE(Fixture, "tostring_unsee_ttv_if_array")
{
CheckResult result = check(R"(
local x: {string}
-- This code is constructed very specifically to use the same (by pointer
-- identity) type in the function twice.
local y: (typeof(x), typeof(x)) -> ()
)");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK(toString(requireType("y")) == "({string}, {string}) -> ()");
}
TEST_CASE_FIXTURE(Fixture, "tostring_error_mismatch")
{
CheckResult result = check(R"(
Sync to upstream/release/614 (#1173) # What's changed? Add program argument passing to scripts run using the Luau REPL! You can now pass `--program-args` (or shorthand `-a`) to the REPL which will treat all remaining arguments as arguments to pass to executed scripts. These values can be accessed through variadic argument expansion. You can read these values like so: ``` local args = {...} -- gets you an array of all the arguments ``` For example if we run the following script like `luau test.lua -a test1 test2 test3`: ``` -- test.lua print(...) ``` you should get the output: ``` test1 test2 test3 ``` ### Native Code Generation * Improve A64 lowering for vector operations by using vector instructions * Fix lowering issue in IR value location tracking! - A developer reported a divergence between code run in the VM and Native Code Generation which we have now fixed ### New Type Solver * Apply substitution to type families, and emit new constraints to reduce those further * More progress on reducing comparison (`lt/le`)type families * Resolve two major sources of cyclic types in the new solver ### Miscellaneous * Turned internal compiler errors (ICE's) into warnings and errors ------- 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: Aviral Goel <agoel@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: 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>
2024-02-24 04:08:34 +08:00
--!strict
function f1() : {a : number, b : string, c : { d : number}}
return { a = 1, b = "b", c = {d = "d"}}
Sync to upstream/release/614 (#1173) # What's changed? Add program argument passing to scripts run using the Luau REPL! You can now pass `--program-args` (or shorthand `-a`) to the REPL which will treat all remaining arguments as arguments to pass to executed scripts. These values can be accessed through variadic argument expansion. You can read these values like so: ``` local args = {...} -- gets you an array of all the arguments ``` For example if we run the following script like `luau test.lua -a test1 test2 test3`: ``` -- test.lua print(...) ``` you should get the output: ``` test1 test2 test3 ``` ### Native Code Generation * Improve A64 lowering for vector operations by using vector instructions * Fix lowering issue in IR value location tracking! - A developer reported a divergence between code run in the VM and Native Code Generation which we have now fixed ### New Type Solver * Apply substitution to type families, and emit new constraints to reduce those further * More progress on reducing comparison (`lt/le`)type families * Resolve two major sources of cyclic types in the new solver ### Miscellaneous * Turned internal compiler errors (ICE's) into warnings and errors ------- 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: Aviral Goel <agoel@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: 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>
2024-02-24 04:08:34 +08:00
end
)");
Sync to upstream/release/614 (#1173) # What's changed? Add program argument passing to scripts run using the Luau REPL! You can now pass `--program-args` (or shorthand `-a`) to the REPL which will treat all remaining arguments as arguments to pass to executed scripts. These values can be accessed through variadic argument expansion. You can read these values like so: ``` local args = {...} -- gets you an array of all the arguments ``` For example if we run the following script like `luau test.lua -a test1 test2 test3`: ``` -- test.lua print(...) ``` you should get the output: ``` test1 test2 test3 ``` ### Native Code Generation * Improve A64 lowering for vector operations by using vector instructions * Fix lowering issue in IR value location tracking! - A developer reported a divergence between code run in the VM and Native Code Generation which we have now fixed ### New Type Solver * Apply substitution to type families, and emit new constraints to reduce those further * More progress on reducing comparison (`lt/le`)type families * Resolve two major sources of cyclic types in the new solver ### Miscellaneous * Turned internal compiler errors (ICE's) into warnings and errors ------- 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: Aviral Goel <agoel@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: 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>
2024-02-24 04:08:34 +08:00
std::string expected;
if (FFlag::DebugLuauDeferredConstraintResolution)
expected = R"(Type pack '{ a: number, b: string, c: { d: string } }' could not be converted into '{ a: number, b: string, c: { d: number } }'; at [0][read "c"][read "d"], string is not exactly number)";
else
expected = R"(Type
'{ a: number, b: string, c: { d: string } }'
could not be converted into
'{| a: number, b: string, c: {| d: number |} |}'
caused by:
Property 'c' is not compatible.
Type
'{ d: string }'
could not be converted into
'{| d: number |}'
caused by:
Property 'd' is not compatible.
Type 'string' could not be converted into 'number' in an invariant context)";
LUAU_REQUIRE_ERROR_COUNT(1, result);
Sync to upstream/release/611 (#1160) # What's changed? ### Native Code Generation * Fixed an UAF relating to reusing a hash key after a weak table has undergone some GC. * Fixed a bounds check on arm64 to allow access to the last byte of a buffer. ### New Type Solver * Type states now preserves error-suppression, i.e. `local x: any = 5` and `x.foo` does not error. * Made error-suppression logic in subtyping more accurate. * Subtyping now knows how to reduce type families. * Fixed function call overload resolution so that the return type resolves to the correct overload. * Fixed a case where we attempted to reduce irreducible type families a few too many times, leading to duplicate errors. * Type checker needs to type check annotations in function signatures to be able to report errors relating to those annotations. * Fixed an UAF from a pointer to stack-allocated data in Subtyping's `explainReasonings`. ### Nonstrict Type Checker * Fixed a crash when calling a checked function of the form `math.abs` with an incorrect argument type. * Fixed a crash when calling a checked function with a number of arguments that did not exactly match the number of parameters required. --- ### Internal Contributors Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> --------- Co-authored-by: Aaron Weiss <aaronweiss@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>
2024-02-03 05:32:42 +08:00
std::string actual = toString(result.errors[0]);
CHECK(expected == actual);
}
Sync to upstream/release/600 (#1076) ### What's Changed - Improve readability of unions and intersections by limiting the number of elements of those types that can be presented on a single line (gated under `FFlag::LuauToStringSimpleCompositeTypesSingleLine`) - Adds a new option to the compiler `--record-stats` to record and output compilation statistics - `if...then...else` expressions are now optimized into `AND/OR` form when possible. ### VM - Add a new `buffer` type to Luau based on the [buffer RFC](https://github.com/Roblox/luau/pull/739) and additional C API functions to work with it; this release does not include the library. - Internal C API to work with string buffers has been updated to align with Lua version more closely ### Native Codegen - Added support for new X64 instruction (rev) and new A64 instruction (bswap) in the assembler - Simplified the way numerical loop condition is translated to IR ### New Type Solver - Operator inference now handled by type families - Created a new system called `Type Paths` to explain why subtyping tests fail in order to improve the quality of error messages. - Systematic changes to implement Data Flow analysis in the new solver (`Breadcrumb` removed and replaced with `RefinementKey`) --- 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: Aviral Goel <agoel@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Vighnesh Vijay <vvijay@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com>
2023-10-21 09:10:30 +08:00
TEST_CASE_FIXTURE(Fixture, "checked_fn_toString")
{
ScopedFastFlag flags[] = {
Sync to upstream/release/605 (#1118) - Implemented [Require by String with Relative Paths](https://github.com/luau-lang/rfcs/blob/master/docs/new-require-by-string-semantics.md) RFC - Implemented [Require by String with Aliases](https://github.com/luau-lang/rfcs/blob/master/docs/require-by-string-aliases.md) RFC with support for `paths` and `alias` arrays in .luarc - Added SUBRK and DIVRK bytecode instructions to speed up constant-number and constant/number operations - Added `--vector-lib`, `--vector-ctor` and `--vector-type` options to luau-compile to support code with vectors New Solver - Correctness fixes to subtyping - Improvements to dataflow analysis Native Code Generation - Added bytecode analysis pass to predict type tags used in operations - Fixed rare cases of numerical loops being generated without an interrupt instruction - Restored optimization data propagation into the linear block - Duplicate buffer length checks are optimized away Miscellaneous - Small performance improvements to new non-strict mode - Introduced more scripts for fuzzing Luau and processing the results, including fuzzer build support for CMake Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@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: 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: 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>
2023-12-02 15:46:57 +08:00
{FFlag::LuauCheckedFunctionSyntax, true},
{FFlag::DebugLuauDeferredConstraintResolution, true},
Sync to upstream/release/600 (#1076) ### What's Changed - Improve readability of unions and intersections by limiting the number of elements of those types that can be presented on a single line (gated under `FFlag::LuauToStringSimpleCompositeTypesSingleLine`) - Adds a new option to the compiler `--record-stats` to record and output compilation statistics - `if...then...else` expressions are now optimized into `AND/OR` form when possible. ### VM - Add a new `buffer` type to Luau based on the [buffer RFC](https://github.com/Roblox/luau/pull/739) and additional C API functions to work with it; this release does not include the library. - Internal C API to work with string buffers has been updated to align with Lua version more closely ### Native Codegen - Added support for new X64 instruction (rev) and new A64 instruction (bswap) in the assembler - Simplified the way numerical loop condition is translated to IR ### New Type Solver - Operator inference now handled by type families - Created a new system called `Type Paths` to explain why subtyping tests fail in order to improve the quality of error messages. - Systematic changes to implement Data Flow analysis in the new solver (`Breadcrumb` removed and replaced with `RefinementKey`) --- 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: Aviral Goel <agoel@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Vighnesh Vijay <vvijay@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com>
2023-10-21 09:10:30 +08:00
};
auto _result = loadDefinition(R"(
declare function @checked abs(n: number) : number
)");
auto result = check(Mode::Nonstrict, R"(
local f = abs
)");
LUAU_REQUIRE_NO_ERRORS(result);
TypeId fn = requireType("f");
CHECK("@checked (number) -> number" == toString(fn));
}
Sync to upstream/release/614 (#1173) # What's changed? Add program argument passing to scripts run using the Luau REPL! You can now pass `--program-args` (or shorthand `-a`) to the REPL which will treat all remaining arguments as arguments to pass to executed scripts. These values can be accessed through variadic argument expansion. You can read these values like so: ``` local args = {...} -- gets you an array of all the arguments ``` For example if we run the following script like `luau test.lua -a test1 test2 test3`: ``` -- test.lua print(...) ``` you should get the output: ``` test1 test2 test3 ``` ### Native Code Generation * Improve A64 lowering for vector operations by using vector instructions * Fix lowering issue in IR value location tracking! - A developer reported a divergence between code run in the VM and Native Code Generation which we have now fixed ### New Type Solver * Apply substitution to type families, and emit new constraints to reduce those further * More progress on reducing comparison (`lt/le`)type families * Resolve two major sources of cyclic types in the new solver ### Miscellaneous * Turned internal compiler errors (ICE's) into warnings and errors ------- 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: Aviral Goel <agoel@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: 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>
2024-02-24 04:08:34 +08:00
TEST_CASE_FIXTURE(Fixture, "read_only_properties")
{
ScopedFastFlag sff{FFlag::DebugLuauDeferredConstraintResolution, true};
CheckResult result = check(R"(
type A = {x: string}
type B = {read x: string}
)");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK("{ x: string }" == toString(requireTypeAlias("A"), {true}));
CHECK("{ read x: string }" == toString(requireTypeAlias("B"), {true}));
}
TEST_CASE_FIXTURE(Fixture, "cycle_rooted_in_a_pack")
{
ScopedFastFlag sff{FFlag::LuauStringifyCyclesRootedAtPacks, true};
TypeArena arena;
TypePackId thePack = arena.addTypePack({builtinTypes->numberType, builtinTypes->numberType});
TypePack* packPtr = getMutable<TypePack>(thePack);
REQUIRE(packPtr);
const TableType::Props theProps = {
{"BaseField", Property::readonly(builtinTypes->unknownType)},
{"BaseMethod", Property::readonly(arena.addType(
FunctionType{
thePack,
arena.addTypePack({})
}
))}
};
TypeId theTable = arena.addType(TableType{theProps, {}, TypeLevel{}, TableState::Sealed});
packPtr->head[0] = theTable;
if (FFlag::DebugLuauDeferredConstraintResolution)
CHECK("tp1 where tp1 = { read BaseField: unknown, read BaseMethod: (tp1) -> () }, number" == toString(thePack));
else
CHECK("tp1 where tp1 = {| BaseField: unknown, BaseMethod: (tp1) -> () |}, number" == toString(thePack));
}
TEST_SUITE_END();