mirror of
https://github.com/luau-lang/luau.git
synced 2024-12-13 13:30:40 +00:00
Merge branch 'master' into merge
This commit is contained in:
commit
f9cfef16c2
15 changed files with 166 additions and 35 deletions
22
.github/workflows/benchmark.yml
vendored
22
.github/workflows/benchmark.yml
vendored
|
@ -41,7 +41,7 @@ jobs:
|
||||||
- name: Build Luau (clang)
|
- name: Build Luau (clang)
|
||||||
run: |
|
run: |
|
||||||
make config=profile clean
|
make config=profile clean
|
||||||
CXX=clang++ make config=profile luau luau-analyze
|
CXX=clang++ make config=profile luau luau-analyze luau-compile
|
||||||
|
|
||||||
- name: Run benchmark (bench-gcc)
|
- name: Run benchmark (bench-gcc)
|
||||||
run: |
|
run: |
|
||||||
|
@ -70,16 +70,16 @@ jobs:
|
||||||
- name: Run benchmark (compile)
|
- name: Run benchmark (compile)
|
||||||
run: |
|
run: |
|
||||||
filter() {
|
filter() {
|
||||||
awk '/.*I\s+refs:\s+[0-9,]+/ {gsub(",", "", $4); X=$4} END {print "SUCCESS: '$1' : " X/1e7 "ms +/- 0% on luau --compile"}'
|
awk '/.*I\s+refs:\s+[0-9,]+/ {gsub(",", "", $4); X=$4} END {print "SUCCESS: '$1' : " X/1e7 "ms +/- 0% on luau-compile"}'
|
||||||
}
|
}
|
||||||
valgrind --tool=callgrind ./luau --compile=null -O0 bench/other/LuauPolyfillMap.lua 2>&1 | filter map-O0 | tee -a compile-output.txt
|
valgrind --tool=callgrind ./luau-compile --null -O0 bench/other/LuauPolyfillMap.lua 2>&1 | filter map-O0 | tee -a compile-output.txt
|
||||||
valgrind --tool=callgrind ./luau --compile=null -O1 bench/other/LuauPolyfillMap.lua 2>&1 | filter map-O1 | tee -a compile-output.txt
|
valgrind --tool=callgrind ./luau-compile --null -O1 bench/other/LuauPolyfillMap.lua 2>&1 | filter map-O1 | tee -a compile-output.txt
|
||||||
valgrind --tool=callgrind ./luau --compile=null -O2 bench/other/LuauPolyfillMap.lua 2>&1 | filter map-O2 | tee -a compile-output.txt
|
valgrind --tool=callgrind ./luau-compile --null -O2 bench/other/LuauPolyfillMap.lua 2>&1 | filter map-O2 | tee -a compile-output.txt
|
||||||
valgrind --tool=callgrind ./luau --compile=codegennull -O2 bench/other/LuauPolyfillMap.lua 2>&1 | filter map-O2-codegen | tee -a compile-output.txt
|
valgrind --tool=callgrind ./luau-compile --codegennull -O2 bench/other/LuauPolyfillMap.lua 2>&1 | filter map-O2-codegen | tee -a compile-output.txt
|
||||||
valgrind --tool=callgrind ./luau --compile=null -O0 bench/other/regex.lua 2>&1 | filter regex-O0 | tee -a compile-output.txt
|
valgrind --tool=callgrind ./luau-compile --null -O0 bench/other/regex.lua 2>&1 | filter regex-O0 | tee -a compile-output.txt
|
||||||
valgrind --tool=callgrind ./luau --compile=null -O1 bench/other/regex.lua 2>&1 | filter regex-O1 | tee -a compile-output.txt
|
valgrind --tool=callgrind ./luau-compile --null -O1 bench/other/regex.lua 2>&1 | filter regex-O1 | tee -a compile-output.txt
|
||||||
valgrind --tool=callgrind ./luau --compile=null -O2 bench/other/regex.lua 2>&1 | filter regex-O2 | tee -a compile-output.txt
|
valgrind --tool=callgrind ./luau-compile --null -O2 bench/other/regex.lua 2>&1 | filter regex-O2 | tee -a compile-output.txt
|
||||||
valgrind --tool=callgrind ./luau --compile=codegennull -O2 bench/other/regex.lua 2>&1 | filter regex-O2-codegen | tee -a compile-output.txt
|
valgrind --tool=callgrind ./luau-compile --codegennull -O2 bench/other/regex.lua 2>&1 | filter regex-O2-codegen | tee -a compile-output.txt
|
||||||
|
|
||||||
- name: Checkout benchmark results
|
- name: Checkout benchmark results
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
@ -124,7 +124,7 @@ jobs:
|
||||||
- name: Store results (compile)
|
- name: Store results (compile)
|
||||||
uses: Roblox/rhysd-github-action-benchmark@v-luau
|
uses: Roblox/rhysd-github-action-benchmark@v-luau
|
||||||
with:
|
with:
|
||||||
name: luau --compile
|
name: luau-compile
|
||||||
tool: "benchmarkluau"
|
tool: "benchmarkluau"
|
||||||
output-file-path: ./compile-output.txt
|
output-file-path: ./compile-output.txt
|
||||||
external-data-json-path: ./gh-pages/compile.json
|
external-data-json-path: ./gh-pages/compile.json
|
||||||
|
|
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
|
@ -42,9 +42,10 @@ jobs:
|
||||||
./luau-tests -ts=Conformance --codegen -O2 --fflags=true
|
./luau-tests -ts=Conformance --codegen -O2 --fflags=true
|
||||||
- name: make cli
|
- name: make cli
|
||||||
run: |
|
run: |
|
||||||
make -j2 config=sanitize werror=1 luau luau-analyze # match config with tests to improve build time
|
make -j2 config=sanitize werror=1 luau luau-analyze luau-compile # match config with tests to improve build time
|
||||||
./luau tests/conformance/assert.lua
|
./luau tests/conformance/assert.lua
|
||||||
./luau-analyze tests/conformance/assert.lua
|
./luau-analyze tests/conformance/assert.lua
|
||||||
|
./luau-compile tests/conformance/assert.lua
|
||||||
|
|
||||||
windows:
|
windows:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
|
@ -76,9 +77,10 @@ jobs:
|
||||||
- name: cmake cli
|
- name: cmake cli
|
||||||
shell: bash # necessary for fail-fast
|
shell: bash # necessary for fail-fast
|
||||||
run: |
|
run: |
|
||||||
cmake --build . --target Luau.Repl.CLI Luau.Analyze.CLI --config Debug # match config with tests to improve build time
|
cmake --build . --target Luau.Repl.CLI Luau.Analyze.CLI Luau.Compile.CLI --config Debug # match config with tests to improve build time
|
||||||
Debug/luau tests/conformance/assert.lua
|
Debug/luau tests/conformance/assert.lua
|
||||||
Debug/luau-analyze tests/conformance/assert.lua
|
Debug/luau-analyze tests/conformance/assert.lua
|
||||||
|
Debug/luau-compile tests/conformance/assert.lua
|
||||||
|
|
||||||
coverage:
|
coverage:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
|
2
.github/workflows/new-release.yml
vendored
2
.github/workflows/new-release.yml
vendored
|
@ -38,7 +38,7 @@ jobs:
|
||||||
- name: configure
|
- name: configure
|
||||||
run: cmake . -DCMAKE_BUILD_TYPE=Release
|
run: cmake . -DCMAKE_BUILD_TYPE=Release
|
||||||
- name: build
|
- name: build
|
||||||
run: cmake --build . --target Luau.Repl.CLI Luau.Analyze.CLI --config Release -j 2
|
run: cmake --build . --target Luau.Repl.CLI Luau.Analyze.CLI Luau.Compile.CLI --config Release -j 2
|
||||||
- name: pack
|
- name: pack
|
||||||
if: matrix.os.name != 'windows'
|
if: matrix.os.name != 'windows'
|
||||||
run: zip luau-${{matrix.os.name}}.zip luau*
|
run: zip luau-${{matrix.os.name}}.zip luau*
|
||||||
|
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
|
@ -22,7 +22,7 @@ jobs:
|
||||||
- name: configure
|
- name: configure
|
||||||
run: cmake . -DCMAKE_BUILD_TYPE=Release
|
run: cmake . -DCMAKE_BUILD_TYPE=Release
|
||||||
- name: build
|
- name: build
|
||||||
run: cmake --build . --target Luau.Repl.CLI Luau.Analyze.CLI --config Release -j 2
|
run: cmake --build . --target Luau.Repl.CLI Luau.Analyze.CLI Luau.Compile.CLI --config Release -j 2
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v2
|
||||||
if: matrix.os.name != 'windows'
|
if: matrix.os.name != 'windows'
|
||||||
with:
|
with:
|
||||||
|
|
|
@ -752,6 +752,7 @@ struct AstJsonEncoder : public AstVisitor
|
||||||
if (node->superName)
|
if (node->superName)
|
||||||
write("superName", *node->superName);
|
write("superName", *node->superName);
|
||||||
PROP(props);
|
PROP(props);
|
||||||
|
PROP(indexer);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
LUAU_FASTINT(LuauCheckRecursionLimit);
|
LUAU_FASTINT(LuauCheckRecursionLimit);
|
||||||
LUAU_FASTFLAG(DebugLuauMagicTypes);
|
LUAU_FASTFLAG(DebugLuauMagicTypes);
|
||||||
|
LUAU_FASTFLAG(LuauParseDeclareClassIndexer);
|
||||||
|
|
||||||
namespace Luau
|
namespace Luau
|
||||||
{
|
{
|
||||||
|
@ -1157,6 +1158,23 @@ ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatDeclareC
|
||||||
|
|
||||||
scope->exportedTypeBindings[className] = TypeFun{{}, classTy};
|
scope->exportedTypeBindings[className] = TypeFun{{}, classTy};
|
||||||
|
|
||||||
|
if (FFlag::LuauParseDeclareClassIndexer && declaredClass->indexer)
|
||||||
|
{
|
||||||
|
RecursionCounter counter{&recursionCount};
|
||||||
|
|
||||||
|
if (recursionCount >= FInt::LuauCheckRecursionLimit)
|
||||||
|
{
|
||||||
|
reportCodeTooComplex(declaredClass->indexer->location);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ctv->indexer = TableIndexer{
|
||||||
|
resolveType(scope, declaredClass->indexer->indexType, /* inTypeArguments */ false),
|
||||||
|
resolveType(scope, declaredClass->indexer->resultType, /* inTypeArguments */ false),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const AstDeclaredClassProp& prop : declaredClass->props)
|
for (const AstDeclaredClassProp& prop : declaredClass->props)
|
||||||
{
|
{
|
||||||
Name propName(prop.name.value);
|
Name propName(prop.name.value);
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
LUAU_FASTFLAG(LuauParseDeclareClassIndexer);
|
||||||
|
|
||||||
static char* allocateString(Luau::Allocator& allocator, std::string_view contents)
|
static char* allocateString(Luau::Allocator& allocator, std::string_view contents)
|
||||||
{
|
{
|
||||||
char* result = (char*)allocator.allocate(contents.size() + 1);
|
char* result = (char*)allocator.allocate(contents.size() + 1);
|
||||||
|
@ -227,7 +229,17 @@ public:
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return allocator->alloc<AstTypeTable>(Location(), props);
|
AstTableIndexer* indexer = nullptr;
|
||||||
|
if (FFlag::LuauParseDeclareClassIndexer && ctv.indexer)
|
||||||
|
{
|
||||||
|
RecursionCounter counter(&count);
|
||||||
|
|
||||||
|
indexer = allocator->alloc<AstTableIndexer>();
|
||||||
|
indexer->indexType = Luau::visit(*this, ctv.indexer->indexType->ty);
|
||||||
|
indexer->resultType = Luau::visit(*this, ctv.indexer->indexResultType->ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
return allocator->alloc<AstTypeTable>(Location(), props, indexer);
|
||||||
}
|
}
|
||||||
|
|
||||||
AstType* operator()(const FunctionType& ftv)
|
AstType* operator()(const FunctionType& ftv)
|
||||||
|
|
|
@ -41,6 +41,7 @@ LUAU_FASTFLAGVARIABLE(LuauTypecheckTypeguards, false)
|
||||||
LUAU_FASTFLAGVARIABLE(LuauTinyControlFlowAnalysis, false)
|
LUAU_FASTFLAGVARIABLE(LuauTinyControlFlowAnalysis, false)
|
||||||
LUAU_FASTFLAGVARIABLE(LuauTypecheckClassTypeIndexers, false)
|
LUAU_FASTFLAGVARIABLE(LuauTypecheckClassTypeIndexers, false)
|
||||||
LUAU_FASTFLAGVARIABLE(LuauAlwaysCommitInferencesOfFunctionCalls, false)
|
LUAU_FASTFLAGVARIABLE(LuauAlwaysCommitInferencesOfFunctionCalls, false)
|
||||||
|
LUAU_FASTFLAG(LuauParseDeclareClassIndexer)
|
||||||
|
|
||||||
namespace Luau
|
namespace Luau
|
||||||
{
|
{
|
||||||
|
@ -1757,6 +1758,9 @@ ControlFlow TypeChecker::check(const ScopePtr& scope, const AstStatDeclareClass&
|
||||||
if (!ctv->metatable)
|
if (!ctv->metatable)
|
||||||
ice("No metatable for declared class");
|
ice("No metatable for declared class");
|
||||||
|
|
||||||
|
if (const auto& indexer = declaredClass.indexer; FFlag::LuauParseDeclareClassIndexer && indexer)
|
||||||
|
ctv->indexer = TableIndexer(resolveType(scope, *indexer->indexType), resolveType(scope, *indexer->resultType));
|
||||||
|
|
||||||
TableType* metatable = getMutable<TableType>(*ctv->metatable);
|
TableType* metatable = getMutable<TableType>(*ctv->metatable);
|
||||||
for (const AstDeclaredClassProp& prop : declaredClass.props)
|
for (const AstDeclaredClassProp& prop : declaredClass.props)
|
||||||
{
|
{
|
||||||
|
|
|
@ -801,12 +801,20 @@ struct AstDeclaredClassProp
|
||||||
bool isMethod = false;
|
bool isMethod = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AstTableIndexer
|
||||||
|
{
|
||||||
|
AstType* indexType;
|
||||||
|
AstType* resultType;
|
||||||
|
Location location;
|
||||||
|
};
|
||||||
|
|
||||||
class AstStatDeclareClass : public AstStat
|
class AstStatDeclareClass : public AstStat
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LUAU_RTTI(AstStatDeclareClass)
|
LUAU_RTTI(AstStatDeclareClass)
|
||||||
|
|
||||||
AstStatDeclareClass(const Location& location, const AstName& name, std::optional<AstName> superName, const AstArray<AstDeclaredClassProp>& props);
|
AstStatDeclareClass(const Location& location, const AstName& name, std::optional<AstName> superName, const AstArray<AstDeclaredClassProp>& props,
|
||||||
|
AstTableIndexer* indexer = nullptr);
|
||||||
|
|
||||||
void visit(AstVisitor* visitor) override;
|
void visit(AstVisitor* visitor) override;
|
||||||
|
|
||||||
|
@ -814,6 +822,7 @@ public:
|
||||||
std::optional<AstName> superName;
|
std::optional<AstName> superName;
|
||||||
|
|
||||||
AstArray<AstDeclaredClassProp> props;
|
AstArray<AstDeclaredClassProp> props;
|
||||||
|
AstTableIndexer* indexer;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AstType : public AstNode
|
class AstType : public AstNode
|
||||||
|
@ -862,13 +871,6 @@ struct AstTableProp
|
||||||
AstType* type;
|
AstType* type;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstTableIndexer
|
|
||||||
{
|
|
||||||
AstType* indexType;
|
|
||||||
AstType* resultType;
|
|
||||||
Location location;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AstTypeTable : public AstType
|
class AstTypeTable : public AstType
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -714,12 +714,13 @@ void AstStatDeclareFunction::visit(AstVisitor* visitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AstStatDeclareClass::AstStatDeclareClass(
|
AstStatDeclareClass::AstStatDeclareClass(const Location& location, const AstName& name, std::optional<AstName> superName,
|
||||||
const Location& location, const AstName& name, std::optional<AstName> superName, const AstArray<AstDeclaredClassProp>& props)
|
const AstArray<AstDeclaredClassProp>& props, AstTableIndexer* indexer)
|
||||||
: AstStat(ClassIndex(), location)
|
: AstStat(ClassIndex(), location)
|
||||||
, name(name)
|
, name(name)
|
||||||
, superName(superName)
|
, superName(superName)
|
||||||
, props(props)
|
, props(props)
|
||||||
|
, indexer(indexer)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
// See docs/SyntaxChanges.md for an explanation.
|
// See docs/SyntaxChanges.md for an explanation.
|
||||||
LUAU_FASTINTVARIABLE(LuauRecursionLimit, 1000)
|
LUAU_FASTINTVARIABLE(LuauRecursionLimit, 1000)
|
||||||
LUAU_FASTINTVARIABLE(LuauParseErrorLimit, 100)
|
LUAU_FASTINTVARIABLE(LuauParseErrorLimit, 100)
|
||||||
|
LUAU_FASTFLAGVARIABLE(LuauParseDeclareClassIndexer, false)
|
||||||
|
|
||||||
#define ERROR_INVALID_INTERP_DOUBLE_BRACE "Double braces are not permitted within interpolated strings. Did you mean '\\{'?"
|
#define ERROR_INVALID_INTERP_DOUBLE_BRACE "Double braces are not permitted within interpolated strings. Did you mean '\\{'?"
|
||||||
|
|
||||||
|
@ -877,6 +878,7 @@ AstStat* Parser::parseDeclaration(const Location& start)
|
||||||
}
|
}
|
||||||
|
|
||||||
TempVector<AstDeclaredClassProp> props(scratchDeclaredClassProps);
|
TempVector<AstDeclaredClassProp> props(scratchDeclaredClassProps);
|
||||||
|
AstTableIndexer* indexer = nullptr;
|
||||||
|
|
||||||
while (lexer.current().type != Lexeme::ReservedEnd)
|
while (lexer.current().type != Lexeme::ReservedEnd)
|
||||||
{
|
{
|
||||||
|
@ -885,7 +887,8 @@ AstStat* Parser::parseDeclaration(const Location& start)
|
||||||
{
|
{
|
||||||
props.push_back(parseDeclaredClassMethod());
|
props.push_back(parseDeclaredClassMethod());
|
||||||
}
|
}
|
||||||
else if (lexer.current().type == '[')
|
else if (lexer.current().type == '[' && (!FFlag::LuauParseDeclareClassIndexer || lexer.lookahead().type == Lexeme::RawString ||
|
||||||
|
lexer.lookahead().type == Lexeme::QuotedString))
|
||||||
{
|
{
|
||||||
const Lexeme begin = lexer.current();
|
const Lexeme begin = lexer.current();
|
||||||
nextLexeme(); // [
|
nextLexeme(); // [
|
||||||
|
@ -904,6 +907,22 @@ AstStat* Parser::parseDeclaration(const Location& start)
|
||||||
else
|
else
|
||||||
report(begin.location, "String literal contains malformed escape sequence");
|
report(begin.location, "String literal contains malformed escape sequence");
|
||||||
}
|
}
|
||||||
|
else if (lexer.current().type == '[' && FFlag::LuauParseDeclareClassIndexer)
|
||||||
|
{
|
||||||
|
if (indexer)
|
||||||
|
{
|
||||||
|
// maybe we don't need to parse the entire badIndexer...
|
||||||
|
// however, we either have { or [ to lint, not the entire table type or the bad indexer.
|
||||||
|
AstTableIndexer* badIndexer = parseTableIndexer();
|
||||||
|
|
||||||
|
// we lose all additional indexer expressions from the AST after error recovery here
|
||||||
|
report(badIndexer->location, "Cannot have more than one class indexer");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
indexer = parseTableIndexer();
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Name propName = parseName("property name");
|
Name propName = parseName("property name");
|
||||||
|
@ -916,7 +935,7 @@ AstStat* Parser::parseDeclaration(const Location& start)
|
||||||
Location classEnd = lexer.current().location;
|
Location classEnd = lexer.current().location;
|
||||||
nextLexeme(); // skip past `end`
|
nextLexeme(); // skip past `end`
|
||||||
|
|
||||||
return allocator.alloc<AstStatDeclareClass>(Location(classStart, classEnd), className.name, superName, copy(props));
|
return allocator.alloc<AstStatDeclareClass>(Location(classStart, classEnd), className.name, superName, copy(props), indexer);
|
||||||
}
|
}
|
||||||
else if (std::optional<Name> globalName = parseNameOpt("global variable name"))
|
else if (std::optional<Name> globalName = parseNameOpt("global variable name"))
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,7 +24,7 @@ You can install and run Luau by downloading the compiled binaries from [a recent
|
||||||
Alternatively, you can use one of the packaged distributions (note that these are not maintained by Luau development team):
|
Alternatively, you can use one of the packaged distributions (note that these are not maintained by Luau development team):
|
||||||
|
|
||||||
- macOS: [Install Homebrew](https://docs.brew.sh/Installation) and run `brew install luau`
|
- macOS: [Install Homebrew](https://docs.brew.sh/Installation) and run `brew install luau`
|
||||||
- Arch Linux: Run `pacman -S luau`
|
- Arch Linux: From the AUR (Arch Linux User Repository), install one of these packages via a AUR helper or manually (by cloning their repo and using ``makepkg``): [luau](https://aur.archlinux.org/packages/luau) (manual build), [luau-git](https://aur.archlinux.org/packages/luau-git) (manual build by cloning this repo), or [luau-bin](https://aur.archlinux.org/packages/luau-bin) (pre-built binaries from releases)
|
||||||
- Alpine Linux: [Enable community repositories](https://wiki.alpinelinux.org/w/index.php?title=Enable_Community_Repository) and run `apk add luau`
|
- Alpine Linux: [Enable community repositories](https://wiki.alpinelinux.org/w/index.php?title=Enable_Community_Repository) and run `apk add luau`
|
||||||
|
|
||||||
After installing, you will want to validate the installation was successful by running the test case [here](https://luau-lang.org/getting-started).
|
After installing, you will want to validate the installation was successful by running the test case [here](https://luau-lang.org/getting-started).
|
||||||
|
|
|
@ -432,11 +432,11 @@ TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatDeclareClass")
|
||||||
REQUIRE(2 == root->body.size);
|
REQUIRE(2 == root->body.size);
|
||||||
|
|
||||||
std::string_view expected1 =
|
std::string_view expected1 =
|
||||||
R"({"type":"AstStatDeclareClass","location":"1,22 - 4,11","name":"Foo","props":[{"name":"prop","type":"AstDeclaredClassProp","luauType":{"type":"AstTypeReference","location":"2,18 - 2,24","name":"number","nameLocation":"2,18 - 2,24","parameters":[]}},{"name":"method","type":"AstDeclaredClassProp","luauType":{"type":"AstTypeFunction","location":"3,21 - 4,11","generics":[],"genericPacks":[],"argTypes":{"type":"AstTypeList","types":[{"type":"AstTypeReference","location":"3,39 - 3,45","name":"number","nameLocation":"3,39 - 3,45","parameters":[]}]},"returnTypes":{"type":"AstTypeList","types":[{"type":"AstTypeReference","location":"3,48 - 3,54","name":"string","nameLocation":"3,48 - 3,54","parameters":[]}]}}}]})";
|
R"({"type":"AstStatDeclareClass","location":"1,22 - 4,11","name":"Foo","props":[{"name":"prop","type":"AstDeclaredClassProp","luauType":{"type":"AstTypeReference","location":"2,18 - 2,24","name":"number","nameLocation":"2,18 - 2,24","parameters":[]}},{"name":"method","type":"AstDeclaredClassProp","luauType":{"type":"AstTypeFunction","location":"3,21 - 4,11","generics":[],"genericPacks":[],"argTypes":{"type":"AstTypeList","types":[{"type":"AstTypeReference","location":"3,39 - 3,45","name":"number","nameLocation":"3,39 - 3,45","parameters":[]}]},"returnTypes":{"type":"AstTypeList","types":[{"type":"AstTypeReference","location":"3,48 - 3,54","name":"string","nameLocation":"3,48 - 3,54","parameters":[]}]}}}],"indexer":null})";
|
||||||
CHECK(toJson(root->body.data[0]) == expected1);
|
CHECK(toJson(root->body.data[0]) == expected1);
|
||||||
|
|
||||||
std::string_view expected2 =
|
std::string_view expected2 =
|
||||||
R"({"type":"AstStatDeclareClass","location":"6,22 - 8,11","name":"Bar","superName":"Foo","props":[{"name":"prop2","type":"AstDeclaredClassProp","luauType":{"type":"AstTypeReference","location":"7,19 - 7,25","name":"string","nameLocation":"7,19 - 7,25","parameters":[]}}]})";
|
R"({"type":"AstStatDeclareClass","location":"6,22 - 8,11","name":"Bar","superName":"Foo","props":[{"name":"prop2","type":"AstDeclaredClassProp","luauType":{"type":"AstTypeReference","location":"7,19 - 7,25","name":"string","nameLocation":"7,19 - 7,25","parameters":[]}}],"indexer":null})";
|
||||||
CHECK(toJson(root->body.data[1]) == expected2);
|
CHECK(toJson(root->body.data[1]) == expected2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,8 @@ TEST_SUITE_BEGIN("AllocatorTests");
|
||||||
TEST_CASE("allocator_can_be_moved")
|
TEST_CASE("allocator_can_be_moved")
|
||||||
{
|
{
|
||||||
Counter* c = nullptr;
|
Counter* c = nullptr;
|
||||||
auto inner = [&]() {
|
auto inner = [&]()
|
||||||
|
{
|
||||||
Luau::Allocator allocator;
|
Luau::Allocator allocator;
|
||||||
c = allocator.alloc<Counter>();
|
c = allocator.alloc<Counter>();
|
||||||
Luau::Allocator moved{std::move(allocator)};
|
Luau::Allocator moved{std::move(allocator)};
|
||||||
|
@ -921,7 +922,8 @@ TEST_CASE_FIXTURE(Fixture, "parse_interpolated_string_double_brace_mid")
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "parse_interpolated_string_without_end_brace")
|
TEST_CASE_FIXTURE(Fixture, "parse_interpolated_string_without_end_brace")
|
||||||
{
|
{
|
||||||
auto columnOfEndBraceError = [this](const char* code) {
|
auto columnOfEndBraceError = [this](const char* code)
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
parse(code);
|
parse(code);
|
||||||
|
@ -1882,6 +1884,44 @@ TEST_CASE_FIXTURE(Fixture, "class_method_properties")
|
||||||
CHECK_EQ(2, klass2->props.size);
|
CHECK_EQ(2, klass2->props.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_FIXTURE(Fixture, "class_indexer")
|
||||||
|
{
|
||||||
|
ScopedFastFlag LuauParseDeclareClassIndexer("LuauParseDeclareClassIndexer", true);
|
||||||
|
|
||||||
|
AstStatBlock* stat = parseEx(R"(
|
||||||
|
declare class Foo
|
||||||
|
prop: boolean
|
||||||
|
[string]: number
|
||||||
|
end
|
||||||
|
)")
|
||||||
|
.root;
|
||||||
|
|
||||||
|
REQUIRE_EQ(stat->body.size, 1);
|
||||||
|
|
||||||
|
AstStatDeclareClass* declaredClass = stat->body.data[0]->as<AstStatDeclareClass>();
|
||||||
|
REQUIRE(declaredClass);
|
||||||
|
REQUIRE(declaredClass->indexer);
|
||||||
|
REQUIRE(declaredClass->indexer->indexType->is<AstTypeReference>());
|
||||||
|
CHECK(declaredClass->indexer->indexType->as<AstTypeReference>()->name == "string");
|
||||||
|
REQUIRE(declaredClass->indexer->resultType->is<AstTypeReference>());
|
||||||
|
CHECK(declaredClass->indexer->resultType->as<AstTypeReference>()->name == "number");
|
||||||
|
|
||||||
|
const ParseResult p1 = matchParseError(R"(
|
||||||
|
declare class Foo
|
||||||
|
[string]: number
|
||||||
|
-- can only have one indexer
|
||||||
|
[number]: number
|
||||||
|
end
|
||||||
|
)",
|
||||||
|
"Cannot have more than one class indexer");
|
||||||
|
|
||||||
|
REQUIRE_EQ(1, p1.root->body.size);
|
||||||
|
|
||||||
|
AstStatDeclareClass* klass = p1.root->body.data[0]->as<AstStatDeclareClass>();
|
||||||
|
REQUIRE(klass != nullptr);
|
||||||
|
CHECK(klass->indexer);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "parse_variadics")
|
TEST_CASE_FIXTURE(Fixture, "parse_variadics")
|
||||||
{
|
{
|
||||||
//clang-format off
|
//clang-format off
|
||||||
|
@ -2347,7 +2387,8 @@ public:
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "recovery_of_parenthesized_expressions")
|
TEST_CASE_FIXTURE(Fixture, "recovery_of_parenthesized_expressions")
|
||||||
{
|
{
|
||||||
auto checkAstEquivalence = [this](const char* codeWithErrors, const char* code) {
|
auto checkAstEquivalence = [this](const char* codeWithErrors, const char* code)
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
parse(codeWithErrors);
|
parse(codeWithErrors);
|
||||||
|
@ -2367,7 +2408,8 @@ TEST_CASE_FIXTURE(Fixture, "recovery_of_parenthesized_expressions")
|
||||||
CHECK_EQ(counterWithErrors.count, counter.count);
|
CHECK_EQ(counterWithErrors.count, counter.count);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto checkRecovery = [this, checkAstEquivalence](const char* codeWithErrors, const char* code, unsigned expectedErrorCount) {
|
auto checkRecovery = [this, checkAstEquivalence](const char* codeWithErrors, const char* code, unsigned expectedErrorCount)
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
parse(codeWithErrors);
|
parse(codeWithErrors);
|
||||||
|
|
|
@ -394,6 +394,36 @@ TEST_CASE_FIXTURE(Fixture, "class_definition_string_props")
|
||||||
CHECK_EQ(toString(requireType("y")), "string");
|
CHECK_EQ(toString(requireType("y")), "string");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE_FIXTURE(Fixture, "class_definition_indexer")
|
||||||
|
{
|
||||||
|
ScopedFastFlag LuauParseDeclareClassIndexer("LuauParseDeclareClassIndexer", true);
|
||||||
|
ScopedFastFlag LuauTypecheckClassTypeIndexers("LuauTypecheckClassTypeIndexers", true);
|
||||||
|
|
||||||
|
loadDefinition(R"(
|
||||||
|
declare class Foo
|
||||||
|
[number]: string
|
||||||
|
end
|
||||||
|
)");
|
||||||
|
|
||||||
|
CheckResult result = check(R"(
|
||||||
|
local x: Foo
|
||||||
|
local y = x[1]
|
||||||
|
)");
|
||||||
|
|
||||||
|
LUAU_REQUIRE_NO_ERRORS(result);
|
||||||
|
|
||||||
|
const ClassType* ctv = get<ClassType>(requireType("x"));
|
||||||
|
REQUIRE(ctv != nullptr);
|
||||||
|
|
||||||
|
REQUIRE(bool(ctv->indexer));
|
||||||
|
|
||||||
|
CHECK_EQ(*ctv->indexer->indexType, *builtinTypes->numberType);
|
||||||
|
CHECK_EQ(*ctv->indexer->indexResultType, *builtinTypes->stringType);
|
||||||
|
|
||||||
|
CHECK_EQ(toString(requireType("y")), "string");
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "class_definitions_reference_other_classes")
|
TEST_CASE_FIXTURE(Fixture, "class_definitions_reference_other_classes")
|
||||||
{
|
{
|
||||||
unfreeze(frontend.globals.globalTypes);
|
unfreeze(frontend.globals.globalTypes);
|
||||||
|
|
Loading…
Reference in a new issue