2022-06-03 23:15:45 +01:00
|
|
|
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
|
|
|
#include "Luau/ConstraintGraphBuilder.h"
|
2022-10-21 18:54:01 +01:00
|
|
|
|
2022-08-11 22:01:33 +01:00
|
|
|
#include "Luau/Ast.h"
|
2022-08-18 22:32:08 +01:00
|
|
|
#include "Luau/Common.h"
|
2022-08-11 22:01:33 +01:00
|
|
|
#include "Luau/Constraint.h"
|
2022-10-21 18:54:01 +01:00
|
|
|
#include "Luau/DcrLogger.h"
|
2022-09-02 00:14:03 +01:00
|
|
|
#include "Luau/ModuleResolver.h"
|
2022-07-01 00:52:43 +01:00
|
|
|
#include "Luau/RecursionCounter.h"
|
2022-10-21 18:54:01 +01:00
|
|
|
#include "Luau/Scope.h"
|
|
|
|
#include "Luau/TypeUtils.h"
|
2023-01-04 20:53:17 +00:00
|
|
|
#include "Luau/Type.h"
|
2022-07-01 00:52:43 +01:00
|
|
|
|
2023-02-17 23:41:51 +00:00
|
|
|
#include <algorithm>
|
|
|
|
|
2022-07-01 00:52:43 +01:00
|
|
|
LUAU_FASTINT(LuauCheckRecursionLimit);
|
2022-09-08 23:14:25 +01:00
|
|
|
LUAU_FASTFLAG(DebugLuauLogSolverToJson);
|
2022-09-29 23:23:10 +01:00
|
|
|
LUAU_FASTFLAG(DebugLuauMagicTypes);
|
2023-01-04 20:53:17 +00:00
|
|
|
LUAU_FASTFLAG(LuauNegatedClassTypes);
|
2023-01-20 20:27:03 +00:00
|
|
|
LUAU_FASTFLAG(SupportTypeAliasGoToDeclaration);
|
2022-06-03 23:15:45 +01:00
|
|
|
|
|
|
|
namespace Luau
|
|
|
|
{
|
|
|
|
|
2022-06-17 02:05:14 +01:00
|
|
|
const AstStat* getFallthrough(const AstStat* node); // TypeInfer.cpp
|
2022-06-03 23:15:45 +01:00
|
|
|
|
2022-09-02 00:14:03 +01:00
|
|
|
static std::optional<AstExpr*> matchRequire(const AstExprCall& call)
|
|
|
|
{
|
|
|
|
const char* require = "require";
|
|
|
|
|
|
|
|
if (call.args.size != 1)
|
|
|
|
return std::nullopt;
|
|
|
|
|
|
|
|
const AstExprGlobal* funcAsGlobal = call.func->as<AstExprGlobal>();
|
|
|
|
if (!funcAsGlobal || funcAsGlobal->name != require)
|
|
|
|
return std::nullopt;
|
|
|
|
|
|
|
|
if (call.args.size != 1)
|
|
|
|
return std::nullopt;
|
|
|
|
|
|
|
|
return call.args.data[0];
|
|
|
|
}
|
|
|
|
|
2022-09-23 20:17:25 +01:00
|
|
|
static bool matchSetmetatable(const AstExprCall& call)
|
|
|
|
{
|
|
|
|
const char* smt = "setmetatable";
|
|
|
|
|
|
|
|
if (call.args.size != 2)
|
|
|
|
return false;
|
2022-10-14 20:48:41 +01:00
|
|
|
|
2022-09-23 20:17:25 +01:00
|
|
|
const AstExprGlobal* funcAsGlobal = call.func->as<AstExprGlobal>();
|
|
|
|
if (!funcAsGlobal || funcAsGlobal->name != smt)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-11-10 22:53:13 +00:00
|
|
|
struct TypeGuard
|
|
|
|
{
|
|
|
|
bool isTypeof;
|
|
|
|
AstExpr* target;
|
|
|
|
std::string type;
|
|
|
|
};
|
|
|
|
|
|
|
|
static std::optional<TypeGuard> matchTypeGuard(const AstExprBinary* binary)
|
|
|
|
{
|
|
|
|
if (binary->op != AstExprBinary::CompareEq && binary->op != AstExprBinary::CompareNe)
|
|
|
|
return std::nullopt;
|
|
|
|
|
|
|
|
AstExpr* left = binary->left;
|
|
|
|
AstExpr* right = binary->right;
|
|
|
|
if (right->is<AstExprCall>())
|
|
|
|
std::swap(left, right);
|
|
|
|
|
|
|
|
if (!right->is<AstExprConstantString>())
|
|
|
|
return std::nullopt;
|
|
|
|
|
|
|
|
AstExprCall* call = left->as<AstExprCall>();
|
|
|
|
AstExprConstantString* string = right->as<AstExprConstantString>();
|
|
|
|
if (!call || !string)
|
|
|
|
return std::nullopt;
|
|
|
|
|
|
|
|
AstExprGlobal* callee = call->func->as<AstExprGlobal>();
|
|
|
|
if (!callee)
|
|
|
|
return std::nullopt;
|
|
|
|
|
|
|
|
if (callee->name != "type" && callee->name != "typeof")
|
|
|
|
return std::nullopt;
|
|
|
|
|
|
|
|
if (call->args.size != 1)
|
|
|
|
return std::nullopt;
|
|
|
|
|
|
|
|
return TypeGuard{
|
|
|
|
/*isTypeof*/ callee->name == "typeof",
|
|
|
|
/*target*/ call->args.data[0],
|
|
|
|
/*type*/ std::string(string->value.data, string->value.size),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-02-10 19:40:38 +00:00
|
|
|
static bool matchAssert(const AstExprCall& call)
|
|
|
|
{
|
|
|
|
if (call.args.size < 1)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const AstExprGlobal* funcAsGlobal = call.func->as<AstExprGlobal>();
|
|
|
|
if (!funcAsGlobal || funcAsGlobal->name != "assert")
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-11-10 22:53:13 +00:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
|
|
|
|
struct Checkpoint
|
|
|
|
{
|
|
|
|
size_t offset;
|
|
|
|
};
|
|
|
|
|
|
|
|
Checkpoint checkpoint(const ConstraintGraphBuilder* cgb)
|
|
|
|
{
|
|
|
|
return Checkpoint{cgb->constraints.size()};
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename F>
|
|
|
|
void forEachConstraint(const Checkpoint& start, const Checkpoint& end, const ConstraintGraphBuilder* cgb, F f)
|
|
|
|
{
|
|
|
|
for (size_t i = start.offset; i < end.offset; ++i)
|
|
|
|
f(cgb->constraints[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
2022-09-02 00:14:03 +01:00
|
|
|
ConstraintGraphBuilder::ConstraintGraphBuilder(const ModuleName& moduleName, ModulePtr module, TypeArena* arena,
|
2023-01-04 20:53:17 +00:00
|
|
|
NotNull<ModuleResolver> moduleResolver, NotNull<BuiltinTypes> builtinTypes, NotNull<InternalErrorReporter> ice, const ScopePtr& globalScope,
|
2022-10-21 18:54:01 +01:00
|
|
|
DcrLogger* logger, NotNull<DataFlowGraph> dfg)
|
2022-07-01 00:52:43 +01:00
|
|
|
: moduleName(moduleName)
|
2022-08-11 22:01:33 +01:00
|
|
|
, module(module)
|
2023-01-04 20:53:17 +00:00
|
|
|
, builtinTypes(builtinTypes)
|
2022-06-03 23:15:45 +01:00
|
|
|
, arena(arena)
|
|
|
|
, rootScope(nullptr)
|
2022-10-21 18:54:01 +01:00
|
|
|
, dfg(dfg)
|
2022-09-02 00:14:03 +01:00
|
|
|
, moduleResolver(moduleResolver)
|
2022-07-01 00:52:43 +01:00
|
|
|
, ice(ice)
|
|
|
|
, globalScope(globalScope)
|
2022-09-08 23:14:25 +01:00
|
|
|
, logger(logger)
|
2022-06-03 23:15:45 +01:00
|
|
|
{
|
2022-09-08 23:14:25 +01:00
|
|
|
if (FFlag::DebugLuauLogSolverToJson)
|
|
|
|
LUAU_ASSERT(logger);
|
|
|
|
|
2022-08-18 22:32:08 +01:00
|
|
|
LUAU_ASSERT(module);
|
2022-06-03 23:15:45 +01:00
|
|
|
}
|
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
TypeId ConstraintGraphBuilder::freshType(const ScopePtr& scope)
|
2022-06-03 23:15:45 +01:00
|
|
|
{
|
2023-01-04 20:53:17 +00:00
|
|
|
return arena->addType(FreeType{scope.get()});
|
2022-06-03 23:15:45 +01:00
|
|
|
}
|
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
TypePackId ConstraintGraphBuilder::freshTypePack(const ScopePtr& scope)
|
2022-06-03 23:15:45 +01:00
|
|
|
{
|
2022-07-29 05:24:07 +01:00
|
|
|
FreeTypePack f{scope.get()};
|
2022-06-03 23:15:45 +01:00
|
|
|
return arena->addTypePack(TypePackVar{std::move(f)});
|
|
|
|
}
|
|
|
|
|
2022-08-18 22:32:08 +01:00
|
|
|
ScopePtr ConstraintGraphBuilder::childScope(AstNode* node, const ScopePtr& parent)
|
2022-06-03 23:15:45 +01:00
|
|
|
{
|
2022-07-29 05:24:07 +01:00
|
|
|
auto scope = std::make_shared<Scope>(parent);
|
2022-08-18 22:32:08 +01:00
|
|
|
scopes.emplace_back(node->location, scope);
|
2022-06-03 23:15:45 +01:00
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
scope->returnType = parent->returnType;
|
2022-09-08 23:14:25 +01:00
|
|
|
scope->varargPack = parent->varargPack;
|
2022-08-18 22:32:08 +01:00
|
|
|
|
|
|
|
parent->children.push_back(NotNull{scope.get()});
|
|
|
|
module->astScopes[node] = scope.get();
|
2022-06-03 23:15:45 +01:00
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
return scope;
|
2022-06-03 23:15:45 +01:00
|
|
|
}
|
|
|
|
|
2022-10-21 18:54:01 +01:00
|
|
|
NotNull<Constraint> ConstraintGraphBuilder::addConstraint(const ScopePtr& scope, const Location& location, ConstraintV cv)
|
2022-06-03 23:15:45 +01:00
|
|
|
{
|
2022-11-10 22:53:13 +00:00
|
|
|
return NotNull{constraints.emplace_back(new Constraint{NotNull{scope.get()}, location, std::move(cv)}).get()};
|
2022-06-03 23:15:45 +01:00
|
|
|
}
|
|
|
|
|
2022-10-21 18:54:01 +01:00
|
|
|
NotNull<Constraint> ConstraintGraphBuilder::addConstraint(const ScopePtr& scope, std::unique_ptr<Constraint> c)
|
2022-06-03 23:15:45 +01:00
|
|
|
{
|
2022-11-10 22:53:13 +00:00
|
|
|
return NotNull{constraints.emplace_back(std::move(c)).get()};
|
2022-06-03 23:15:45 +01:00
|
|
|
}
|
|
|
|
|
2022-11-04 17:33:22 +00:00
|
|
|
static void unionRefinements(const std::unordered_map<DefId, TypeId>& lhs, const std::unordered_map<DefId, TypeId>& rhs,
|
|
|
|
std::unordered_map<DefId, TypeId>& dest, NotNull<TypeArena> arena)
|
|
|
|
{
|
|
|
|
for (auto [def, ty] : lhs)
|
|
|
|
{
|
|
|
|
auto rhsIt = rhs.find(def);
|
|
|
|
if (rhsIt == rhs.end())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
std::vector<TypeId> discriminants{{ty, rhsIt->second}};
|
|
|
|
|
|
|
|
if (auto destIt = dest.find(def); destIt != dest.end())
|
|
|
|
discriminants.push_back(destIt->second);
|
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
dest[def] = arena->addType(UnionType{std::move(discriminants)});
|
2022-11-04 17:33:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
static void computeRefinement(const ScopePtr& scope, RefinementId refinement, std::unordered_map<DefId, TypeId>* refis, bool sense,
|
2022-12-02 18:09:59 +00:00
|
|
|
NotNull<TypeArena> arena, bool eq, std::vector<ConstraintV>* constraints)
|
2022-11-04 17:33:22 +00:00
|
|
|
{
|
|
|
|
using RefinementMap = std::unordered_map<DefId, TypeId>;
|
|
|
|
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
if (!refinement)
|
2022-11-04 17:33:22 +00:00
|
|
|
return;
|
2023-02-10 19:40:38 +00:00
|
|
|
else if (auto variadic = get<Variadic>(refinement))
|
|
|
|
{
|
|
|
|
for (RefinementId refi : variadic->refinements)
|
|
|
|
computeRefinement(scope, refi, refis, sense, arena, eq, constraints);
|
|
|
|
}
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
else if (auto negation = get<Negation>(refinement))
|
|
|
|
return computeRefinement(scope, negation->refinement, refis, !sense, arena, eq, constraints);
|
|
|
|
else if (auto conjunction = get<Conjunction>(refinement))
|
2022-11-04 17:33:22 +00:00
|
|
|
{
|
|
|
|
RefinementMap lhsRefis;
|
|
|
|
RefinementMap rhsRefis;
|
|
|
|
|
|
|
|
computeRefinement(scope, conjunction->lhs, sense ? refis : &lhsRefis, sense, arena, eq, constraints);
|
|
|
|
computeRefinement(scope, conjunction->rhs, sense ? refis : &rhsRefis, sense, arena, eq, constraints);
|
|
|
|
|
|
|
|
if (!sense)
|
|
|
|
unionRefinements(lhsRefis, rhsRefis, *refis, arena);
|
|
|
|
}
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
else if (auto disjunction = get<Disjunction>(refinement))
|
2022-11-04 17:33:22 +00:00
|
|
|
{
|
|
|
|
RefinementMap lhsRefis;
|
|
|
|
RefinementMap rhsRefis;
|
|
|
|
|
|
|
|
computeRefinement(scope, disjunction->lhs, sense ? &lhsRefis : refis, sense, arena, eq, constraints);
|
|
|
|
computeRefinement(scope, disjunction->rhs, sense ? &rhsRefis : refis, sense, arena, eq, constraints);
|
|
|
|
|
|
|
|
if (sense)
|
|
|
|
unionRefinements(lhsRefis, rhsRefis, *refis, arena);
|
|
|
|
}
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
else if (auto equivalence = get<Equivalence>(refinement))
|
2022-11-04 17:33:22 +00:00
|
|
|
{
|
|
|
|
computeRefinement(scope, equivalence->lhs, refis, sense, arena, true, constraints);
|
|
|
|
computeRefinement(scope, equivalence->rhs, refis, sense, arena, true, constraints);
|
|
|
|
}
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
else if (auto proposition = get<Proposition>(refinement))
|
2022-11-04 17:33:22 +00:00
|
|
|
{
|
|
|
|
TypeId discriminantTy = proposition->discriminantTy;
|
|
|
|
if (!sense && !eq)
|
2023-01-04 20:53:17 +00:00
|
|
|
discriminantTy = arena->addType(NegationType{proposition->discriminantTy});
|
2022-12-02 18:09:59 +00:00
|
|
|
else if (eq)
|
2022-11-04 17:33:22 +00:00
|
|
|
{
|
2023-01-04 20:53:17 +00:00
|
|
|
discriminantTy = arena->addType(BlockedType{});
|
2022-12-02 18:09:59 +00:00
|
|
|
constraints->push_back(SingletonOrTopTypeConstraint{discriminantTy, proposition->discriminantTy, !sense});
|
2022-11-04 17:33:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (auto it = refis->find(proposition->def); it != refis->end())
|
2023-01-04 20:53:17 +00:00
|
|
|
(*refis)[proposition->def] = arena->addType(IntersectionType{{discriminantTy, it->second}});
|
2022-11-04 17:33:22 +00:00
|
|
|
else
|
|
|
|
(*refis)[proposition->def] = discriminantTy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-02 18:09:59 +00:00
|
|
|
static std::pair<DefId, TypeId> computeDiscriminantType(NotNull<TypeArena> arena, const ScopePtr& scope, DefId def, TypeId discriminantTy)
|
|
|
|
{
|
|
|
|
LUAU_ASSERT(get<Cell>(def));
|
|
|
|
|
|
|
|
while (const Cell* current = get<Cell>(def))
|
|
|
|
{
|
|
|
|
if (!current->field)
|
|
|
|
break;
|
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
TableType::Props props{{current->field->propName, Property{discriminantTy}}};
|
|
|
|
discriminantTy = arena->addType(TableType{std::move(props), std::nullopt, TypeLevel{}, scope.get(), TableState::Sealed});
|
2022-12-02 18:09:59 +00:00
|
|
|
|
|
|
|
def = current->field->parent;
|
|
|
|
current = get<Cell>(def);
|
|
|
|
}
|
|
|
|
|
|
|
|
return {def, discriminantTy};
|
|
|
|
}
|
|
|
|
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
void ConstraintGraphBuilder::applyRefinements(const ScopePtr& scope, Location location, RefinementId refinement)
|
2022-11-04 17:33:22 +00:00
|
|
|
{
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
if (!refinement)
|
2022-11-04 17:33:22 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
std::unordered_map<DefId, TypeId> refinements;
|
2022-12-02 18:09:59 +00:00
|
|
|
std::vector<ConstraintV> constraints;
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
computeRefinement(scope, refinement, &refinements, /*sense*/ true, arena, /*eq*/ false, &constraints);
|
2022-11-04 17:33:22 +00:00
|
|
|
|
|
|
|
for (auto [def, discriminantTy] : refinements)
|
|
|
|
{
|
2022-12-02 18:09:59 +00:00
|
|
|
auto [def2, discriminantTy2] = computeDiscriminantType(arena, scope, def, discriminantTy);
|
|
|
|
std::optional<TypeId> defTy = scope->lookup(def2);
|
2022-11-04 17:33:22 +00:00
|
|
|
if (!defTy)
|
|
|
|
ice->ice("Every DefId must map to a type!");
|
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
TypeId resultTy = arena->addType(IntersectionType{{*defTy, discriminantTy2}});
|
2022-12-02 18:09:59 +00:00
|
|
|
scope->dcrRefinements[def2] = resultTy;
|
2022-11-04 17:33:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& c : constraints)
|
|
|
|
addConstraint(scope, location, c);
|
|
|
|
}
|
|
|
|
|
2022-06-03 23:15:45 +01:00
|
|
|
void ConstraintGraphBuilder::visit(AstStatBlock* block)
|
|
|
|
{
|
|
|
|
LUAU_ASSERT(scopes.empty());
|
|
|
|
LUAU_ASSERT(rootScope == nullptr);
|
2022-08-11 22:01:33 +01:00
|
|
|
ScopePtr scope = std::make_shared<Scope>(globalScope);
|
2022-07-29 05:24:07 +01:00
|
|
|
rootScope = scope.get();
|
|
|
|
scopes.emplace_back(block->location, scope);
|
2022-08-18 22:32:08 +01:00
|
|
|
module->astScopes[block] = NotNull{scope.get()};
|
2022-07-01 00:52:43 +01:00
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
rootScope->returnType = freshTypePack(scope);
|
2022-07-01 00:52:43 +01:00
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
prepopulateGlobalScope(scope, block);
|
2022-06-03 23:15:45 +01:00
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
visitBlockWithoutChildScope(scope, block);
|
2022-07-01 00:52:43 +01:00
|
|
|
}
|
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
void ConstraintGraphBuilder::visitBlockWithoutChildScope(const ScopePtr& scope, AstStatBlock* block)
|
2022-07-01 00:52:43 +01:00
|
|
|
{
|
|
|
|
RecursionCounter counter{&recursionCount};
|
|
|
|
|
|
|
|
if (recursionCount >= FInt::LuauCheckRecursionLimit)
|
|
|
|
{
|
|
|
|
reportCodeTooComplex(block->location);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-08-04 23:35:33 +01:00
|
|
|
std::unordered_map<Name, Location> aliasDefinitionLocations;
|
|
|
|
|
|
|
|
// In order to enable mutually-recursive type aliases, we need to
|
|
|
|
// populate the type bindings before we actually check any of the
|
2023-02-17 23:41:51 +00:00
|
|
|
// alias statements.
|
2022-08-04 23:35:33 +01:00
|
|
|
for (AstStat* stat : block->body)
|
|
|
|
{
|
|
|
|
if (auto alias = stat->as<AstStatTypeAlias>())
|
|
|
|
{
|
2023-02-17 23:41:51 +00:00
|
|
|
if (scope->exportedTypeBindings.count(alias->name.value) || scope->privateTypeBindings.count(alias->name.value))
|
2022-08-04 23:35:33 +01:00
|
|
|
{
|
|
|
|
auto it = aliasDefinitionLocations.find(alias->name.value);
|
|
|
|
LUAU_ASSERT(it != aliasDefinitionLocations.end());
|
|
|
|
reportError(alias->location, DuplicateTypeDefinition{alias->name.value, it->second});
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-02-17 23:41:51 +00:00
|
|
|
ScopePtr defnScope = childScope(alias, scope);
|
2022-08-04 23:35:33 +01:00
|
|
|
|
2023-02-17 23:41:51 +00:00
|
|
|
TypeId initialType = arena->addType(BlockedType{});
|
|
|
|
TypeFun initialFun{initialType};
|
2022-08-04 23:35:33 +01:00
|
|
|
|
2023-02-17 23:41:51 +00:00
|
|
|
for (const auto& [name, gen] : createGenerics(defnScope, alias->generics, /* useCache */ true))
|
2022-08-04 23:35:33 +01:00
|
|
|
{
|
|
|
|
initialFun.typeParams.push_back(gen);
|
2022-08-11 22:01:33 +01:00
|
|
|
defnScope->privateTypeBindings[name] = TypeFun{gen.ty};
|
2022-08-04 23:35:33 +01:00
|
|
|
}
|
|
|
|
|
2023-02-17 23:41:51 +00:00
|
|
|
for (const auto& [name, genPack] : createGenericPacks(defnScope, alias->genericPacks, /* useCache */ true))
|
2022-08-04 23:35:33 +01:00
|
|
|
{
|
|
|
|
initialFun.typePackParams.push_back(genPack);
|
2022-08-11 22:01:33 +01:00
|
|
|
defnScope->privateTypePackBindings[name] = genPack.tp;
|
2022-08-04 23:35:33 +01:00
|
|
|
}
|
|
|
|
|
2023-02-17 23:41:51 +00:00
|
|
|
if (alias->exported)
|
|
|
|
scope->exportedTypeBindings[alias->name.value] = std::move(initialFun);
|
|
|
|
else
|
|
|
|
scope->privateTypeBindings[alias->name.value] = std::move(initialFun);
|
|
|
|
|
2022-08-04 23:35:33 +01:00
|
|
|
astTypeAliasDefiningScopes[alias] = defnScope;
|
|
|
|
aliasDefinitionLocations[alias->name.value] = alias->location;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-01 00:52:43 +01:00
|
|
|
for (AstStat* stat : block->body)
|
|
|
|
visit(scope, stat);
|
2022-06-03 23:15:45 +01:00
|
|
|
}
|
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStat* stat)
|
2022-06-03 23:15:45 +01:00
|
|
|
{
|
2022-07-01 00:52:43 +01:00
|
|
|
RecursionLimiter limiter{&recursionCount, FInt::LuauCheckRecursionLimit};
|
2022-06-03 23:15:45 +01:00
|
|
|
|
|
|
|
if (auto s = stat->as<AstStatBlock>())
|
|
|
|
visit(scope, s);
|
2023-02-17 23:41:51 +00:00
|
|
|
else if (auto i = stat->as<AstStatIf>())
|
|
|
|
visit(scope, i);
|
2022-08-11 22:01:33 +01:00
|
|
|
else if (auto s = stat->as<AstStatWhile>())
|
|
|
|
visit(scope, s);
|
2022-08-18 22:32:08 +01:00
|
|
|
else if (auto s = stat->as<AstStatRepeat>())
|
|
|
|
visit(scope, s);
|
2023-02-17 23:41:51 +00:00
|
|
|
else if (stat->is<AstStatBreak>() || stat->is<AstStatContinue>())
|
|
|
|
{
|
|
|
|
// Nothing
|
|
|
|
}
|
2022-06-03 23:15:45 +01:00
|
|
|
else if (auto r = stat->as<AstStatReturn>())
|
|
|
|
visit(scope, r);
|
2023-02-17 23:41:51 +00:00
|
|
|
else if (auto e = stat->as<AstStatExpr>())
|
|
|
|
checkPack(scope, e->expr);
|
|
|
|
else if (auto s = stat->as<AstStatLocal>())
|
|
|
|
visit(scope, s);
|
|
|
|
else if (auto s = stat->as<AstStatFor>())
|
|
|
|
visit(scope, s);
|
|
|
|
else if (auto s = stat->as<AstStatForIn>())
|
|
|
|
visit(scope, s);
|
2022-06-17 02:05:14 +01:00
|
|
|
else if (auto a = stat->as<AstStatAssign>())
|
|
|
|
visit(scope, a);
|
2022-08-18 22:32:08 +01:00
|
|
|
else if (auto a = stat->as<AstStatCompoundAssign>())
|
|
|
|
visit(scope, a);
|
2023-02-17 23:41:51 +00:00
|
|
|
else if (auto f = stat->as<AstStatFunction>())
|
|
|
|
visit(scope, f);
|
|
|
|
else if (auto f = stat->as<AstStatLocalFunction>())
|
|
|
|
visit(scope, f);
|
2022-06-24 02:56:00 +01:00
|
|
|
else if (auto a = stat->as<AstStatTypeAlias>())
|
|
|
|
visit(scope, a);
|
2022-08-04 23:35:33 +01:00
|
|
|
else if (auto s = stat->as<AstStatDeclareGlobal>())
|
|
|
|
visit(scope, s);
|
|
|
|
else if (auto s = stat->as<AstStatDeclareFunction>())
|
|
|
|
visit(scope, s);
|
2023-02-17 23:41:51 +00:00
|
|
|
else if (auto s = stat->as<AstStatDeclareClass>())
|
|
|
|
visit(scope, s);
|
2022-09-29 23:23:10 +01:00
|
|
|
else if (auto s = stat->as<AstStatError>())
|
|
|
|
visit(scope, s);
|
2022-06-03 23:15:45 +01:00
|
|
|
else
|
2023-02-17 23:41:51 +00:00
|
|
|
LUAU_ASSERT(0 && "Internal error: Unknown AstStat type");
|
2022-06-03 23:15:45 +01:00
|
|
|
}
|
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatLocal* local)
|
2022-06-03 23:15:45 +01:00
|
|
|
{
|
|
|
|
std::vector<TypeId> varTypes;
|
2022-10-21 18:54:01 +01:00
|
|
|
varTypes.reserve(local->vars.size);
|
2022-06-03 23:15:45 +01:00
|
|
|
|
2023-01-27 22:28:31 +00:00
|
|
|
// Used to name the first value type, even if it's not placed in varTypes,
|
|
|
|
// for the purpose of synthetic name attribution.
|
|
|
|
std::optional<TypeId> firstValueType;
|
|
|
|
|
2022-06-03 23:15:45 +01:00
|
|
|
for (AstLocal* local : local->vars)
|
|
|
|
{
|
2022-09-23 20:17:25 +01:00
|
|
|
TypeId ty = nullptr;
|
2022-06-24 02:56:00 +01:00
|
|
|
|
|
|
|
if (local->annotation)
|
2023-01-20 20:27:03 +00:00
|
|
|
ty = resolveType(scope, local->annotation, /* inTypeArguments */ false);
|
2022-06-24 02:56:00 +01:00
|
|
|
|
2022-06-03 23:15:45 +01:00
|
|
|
varTypes.push_back(ty);
|
|
|
|
}
|
|
|
|
|
2022-06-17 02:05:14 +01:00
|
|
|
for (size_t i = 0; i < local->values.size; ++i)
|
2022-06-03 23:15:45 +01:00
|
|
|
{
|
2022-08-25 22:53:50 +01:00
|
|
|
AstExpr* value = local->values.data[i];
|
2022-09-23 20:17:25 +01:00
|
|
|
const bool hasAnnotation = i < local->vars.size && nullptr != local->vars.data[i]->annotation;
|
|
|
|
|
2022-08-25 22:53:50 +01:00
|
|
|
if (value->is<AstExprConstantNil>())
|
2022-06-17 02:05:14 +01:00
|
|
|
{
|
2022-11-04 17:33:22 +00:00
|
|
|
// HACK: we leave nil-initialized things floating under the
|
|
|
|
// assumption that they will later be populated.
|
|
|
|
//
|
|
|
|
// See the test TypeInfer/infer_locals_with_nil_value. Better flow
|
|
|
|
// awareness should make this obsolete.
|
2022-10-21 18:54:01 +01:00
|
|
|
|
|
|
|
if (!varTypes[i])
|
|
|
|
varTypes[i] = freshType(scope);
|
2022-06-17 02:05:14 +01:00
|
|
|
}
|
2022-11-04 17:33:22 +00:00
|
|
|
// Only function calls and vararg expressions can produce packs. All
|
|
|
|
// other expressions produce exactly one value.
|
|
|
|
else if (i != local->values.size - 1 || (!value->is<AstExprCall>() && !value->is<AstExprVarargs>()))
|
|
|
|
{
|
|
|
|
std::optional<TypeId> expectedType;
|
|
|
|
if (hasAnnotation)
|
|
|
|
expectedType = varTypes.at(i);
|
|
|
|
|
|
|
|
TypeId exprType = check(scope, value, expectedType).ty;
|
|
|
|
if (i < varTypes.size())
|
|
|
|
{
|
|
|
|
if (varTypes[i])
|
|
|
|
addConstraint(scope, local->location, SubtypeConstraint{exprType, varTypes[i]});
|
|
|
|
else
|
|
|
|
varTypes[i] = exprType;
|
|
|
|
}
|
2023-01-27 22:28:31 +00:00
|
|
|
|
|
|
|
if (i == 0)
|
|
|
|
firstValueType = exprType;
|
2022-11-04 17:33:22 +00:00
|
|
|
}
|
|
|
|
else
|
2022-06-17 02:05:14 +01:00
|
|
|
{
|
2023-02-17 23:41:51 +00:00
|
|
|
std::vector<std::optional<TypeId>> expectedTypes;
|
2022-09-23 20:17:25 +01:00
|
|
|
if (hasAnnotation)
|
|
|
|
expectedTypes.insert(begin(expectedTypes), begin(varTypes) + i, end(varTypes));
|
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
TypePackId exprPack = checkPack(scope, value, expectedTypes).tp;
|
2022-06-17 02:05:14 +01:00
|
|
|
|
|
|
|
if (i < local->vars.size)
|
|
|
|
{
|
2023-01-04 20:53:17 +00:00
|
|
|
TypePack packTypes = extendTypePack(*arena, builtinTypes, exprPack, varTypes.size() - i);
|
2022-10-21 18:54:01 +01:00
|
|
|
|
|
|
|
// fill out missing values in varTypes with values from exprPack
|
|
|
|
for (size_t j = i; j < varTypes.size(); ++j)
|
|
|
|
{
|
|
|
|
if (!varTypes[j])
|
|
|
|
{
|
2022-12-02 18:09:59 +00:00
|
|
|
if (j - i < packTypes.head.size())
|
|
|
|
varTypes[j] = packTypes.head[j - i];
|
2022-10-21 18:54:01 +01:00
|
|
|
else
|
|
|
|
varTypes[j] = freshType(scope);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-17 02:05:14 +01:00
|
|
|
std::vector<TypeId> tailValues{varTypes.begin() + i, varTypes.end()};
|
|
|
|
TypePackId tailPack = arena->addTypePack(std::move(tailValues));
|
2022-09-02 00:14:03 +01:00
|
|
|
addConstraint(scope, local->location, PackSubtypeConstraint{exprPack, tailPack});
|
2022-06-17 02:05:14 +01:00
|
|
|
}
|
|
|
|
}
|
2022-09-02 00:14:03 +01:00
|
|
|
}
|
|
|
|
|
2023-01-27 22:28:31 +00:00
|
|
|
if (local->vars.size == 1 && local->values.size == 1 && firstValueType)
|
|
|
|
{
|
|
|
|
AstLocal* var = local->vars.data[0];
|
|
|
|
AstExpr* value = local->values.data[0];
|
|
|
|
|
|
|
|
if (value->is<AstExprTable>())
|
|
|
|
addConstraint(scope, value->location, NameConstraint{*firstValueType, var->name.value, /*synthetic*/ true});
|
|
|
|
else if (const AstExprCall* call = value->as<AstExprCall>())
|
|
|
|
{
|
|
|
|
if (const AstExprGlobal* global = call->func->as<AstExprGlobal>(); global && global->name == "setmetatable")
|
|
|
|
{
|
|
|
|
addConstraint(scope, value->location, NameConstraint{*firstValueType, var->name.value, /*synthetic*/ true});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-21 18:54:01 +01:00
|
|
|
for (size_t i = 0; i < local->vars.size; ++i)
|
|
|
|
{
|
|
|
|
AstLocal* l = local->vars.data[i];
|
|
|
|
Location location = l->location;
|
|
|
|
|
|
|
|
if (!varTypes[i])
|
|
|
|
varTypes[i] = freshType(scope);
|
|
|
|
|
|
|
|
scope->bindings[l] = Binding{varTypes[i], location};
|
|
|
|
|
|
|
|
// HACK: In the greedy solver, we say the type state of a variable is the type annotation itself, but
|
|
|
|
// the actual type state is the corresponding initializer expression (if it exists) or nil otherwise.
|
|
|
|
if (auto def = dfg->getDef(l))
|
|
|
|
scope->dcrRefinements[*def] = varTypes[i];
|
|
|
|
}
|
|
|
|
|
2022-09-02 00:14:03 +01:00
|
|
|
if (local->values.size > 0)
|
|
|
|
{
|
|
|
|
// To correctly handle 'require', we need to import the exported type bindings into the variable 'namespace'.
|
|
|
|
for (size_t i = 0; i < local->values.size && i < local->vars.size; ++i)
|
|
|
|
{
|
|
|
|
const AstExprCall* call = local->values.data[i]->as<AstExprCall>();
|
|
|
|
if (!call)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (auto maybeRequire = matchRequire(*call))
|
|
|
|
{
|
|
|
|
AstExpr* require = *maybeRequire;
|
|
|
|
|
|
|
|
if (auto moduleInfo = moduleResolver->resolveModuleInfo(moduleName, *require))
|
|
|
|
{
|
|
|
|
const Name name{local->vars.data[i]->name.value};
|
|
|
|
|
|
|
|
if (ModulePtr module = moduleResolver->getModule(moduleInfo->name))
|
2023-01-20 20:27:03 +00:00
|
|
|
{
|
2023-02-10 19:40:38 +00:00
|
|
|
scope->importedTypeBindings[name] = module->exportedTypeBindings;
|
2023-01-20 20:27:03 +00:00
|
|
|
if (FFlag::SupportTypeAliasGoToDeclaration)
|
|
|
|
scope->importedModules[name] = moduleName;
|
|
|
|
}
|
2022-09-02 00:14:03 +01:00
|
|
|
}
|
|
|
|
}
|
2022-06-03 23:15:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFor* for_)
|
2022-07-14 23:52:26 +01:00
|
|
|
{
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
if (for_->var->annotation)
|
|
|
|
resolveType(scope, for_->var->annotation, /* inTypeArguments */ false);
|
|
|
|
|
|
|
|
auto inferNumber = [&](AstExpr* expr) {
|
2022-07-14 23:52:26 +01:00
|
|
|
if (!expr)
|
|
|
|
return;
|
2022-08-04 23:35:33 +01:00
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
TypeId t = check(scope, expr).ty;
|
2023-01-04 20:53:17 +00:00
|
|
|
addConstraint(scope, expr->location, SubtypeConstraint{t, builtinTypes->numberType});
|
2022-07-14 23:52:26 +01:00
|
|
|
};
|
|
|
|
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
inferNumber(for_->from);
|
|
|
|
inferNumber(for_->to);
|
|
|
|
inferNumber(for_->step);
|
2022-07-14 23:52:26 +01:00
|
|
|
|
2022-08-18 22:32:08 +01:00
|
|
|
ScopePtr forScope = childScope(for_, scope);
|
2023-01-04 20:53:17 +00:00
|
|
|
forScope->bindings[for_->var] = Binding{builtinTypes->numberType, for_->var->location};
|
2022-07-14 23:52:26 +01:00
|
|
|
|
|
|
|
visit(forScope, for_->body);
|
|
|
|
}
|
|
|
|
|
2022-09-02 00:14:03 +01:00
|
|
|
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatForIn* forIn)
|
|
|
|
{
|
|
|
|
ScopePtr loopScope = childScope(forIn, scope);
|
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
TypePackId iterator = checkPack(scope, forIn->values).tp;
|
2022-09-02 00:14:03 +01:00
|
|
|
|
|
|
|
std::vector<TypeId> variableTypes;
|
|
|
|
variableTypes.reserve(forIn->vars.size);
|
|
|
|
for (AstLocal* var : forIn->vars)
|
|
|
|
{
|
|
|
|
TypeId ty = freshType(loopScope);
|
|
|
|
loopScope->bindings[var] = Binding{ty, var->location};
|
|
|
|
variableTypes.push_back(ty);
|
2022-11-10 22:53:13 +00:00
|
|
|
|
|
|
|
if (auto def = dfg->getDef(var))
|
|
|
|
loopScope->dcrRefinements[*def] = ty;
|
2022-09-02 00:14:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// It is always ok to provide too few variables, so we give this pack a free tail.
|
|
|
|
TypePackId variablePack = arena->addTypePack(std::move(variableTypes), arena->addTypePack(FreeTypePack{loopScope.get()}));
|
|
|
|
|
|
|
|
addConstraint(loopScope, getLocation(forIn->values), IterableConstraint{iterator, variablePack});
|
|
|
|
|
|
|
|
visit(loopScope, forIn->body);
|
|
|
|
}
|
|
|
|
|
2022-08-11 22:01:33 +01:00
|
|
|
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatWhile* while_)
|
|
|
|
{
|
|
|
|
check(scope, while_->condition);
|
|
|
|
|
2022-08-18 22:32:08 +01:00
|
|
|
ScopePtr whileScope = childScope(while_, scope);
|
2022-08-11 22:01:33 +01:00
|
|
|
|
|
|
|
visit(whileScope, while_->body);
|
|
|
|
}
|
|
|
|
|
2022-08-18 22:32:08 +01:00
|
|
|
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatRepeat* repeat)
|
|
|
|
{
|
|
|
|
ScopePtr repeatScope = childScope(repeat, scope);
|
|
|
|
|
|
|
|
visit(repeatScope, repeat->body);
|
|
|
|
|
|
|
|
// The condition does indeed have access to bindings from within the body of
|
|
|
|
// the loop.
|
|
|
|
check(repeatScope, repeat->condition);
|
|
|
|
}
|
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatLocalFunction* function)
|
2022-06-03 23:15:45 +01:00
|
|
|
{
|
|
|
|
// Local
|
|
|
|
// Global
|
|
|
|
// Dotted path
|
|
|
|
// Self?
|
|
|
|
|
|
|
|
TypeId functionType = nullptr;
|
|
|
|
auto ty = scope->lookup(function->name);
|
2022-07-01 00:52:43 +01:00
|
|
|
LUAU_ASSERT(!ty.has_value()); // The parser ensures that every local function has a distinct Symbol for its name.
|
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
functionType = arena->addType(BlockedType{});
|
2022-07-29 05:24:07 +01:00
|
|
|
scope->bindings[function->name] = Binding{functionType, function->name->location};
|
2022-06-03 23:15:45 +01:00
|
|
|
|
2022-07-01 00:52:43 +01:00
|
|
|
FunctionSignature sig = checkFunctionSignature(scope, function->func);
|
2022-07-29 05:24:07 +01:00
|
|
|
sig.bodyScope->bindings[function->name] = Binding{sig.signature, function->func->location};
|
2022-06-03 23:15:45 +01:00
|
|
|
|
2022-12-02 18:09:59 +00:00
|
|
|
Checkpoint start = checkpoint(this);
|
2022-07-01 00:52:43 +01:00
|
|
|
checkFunctionBody(sig.bodyScope, function->func);
|
2022-12-02 18:09:59 +00:00
|
|
|
Checkpoint end = checkpoint(this);
|
2022-06-03 23:15:45 +01:00
|
|
|
|
2022-08-18 22:32:08 +01:00
|
|
|
NotNull<Scope> constraintScope{sig.signatureScope ? sig.signatureScope.get() : sig.bodyScope.get()};
|
2022-09-02 00:14:03 +01:00
|
|
|
std::unique_ptr<Constraint> c =
|
|
|
|
std::make_unique<Constraint>(constraintScope, function->name->location, GeneralizationConstraint{functionType, sig.signature});
|
2022-11-10 22:53:13 +00:00
|
|
|
|
|
|
|
forEachConstraint(start, end, this, [&c](const ConstraintPtr& constraint) {
|
|
|
|
c->dependencies.push_back(NotNull{constraint.get()});
|
|
|
|
});
|
2022-06-17 02:05:14 +01:00
|
|
|
|
|
|
|
addConstraint(scope, std::move(c));
|
|
|
|
}
|
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFunction* function)
|
2022-06-17 02:05:14 +01:00
|
|
|
{
|
|
|
|
// Name could be AstStatLocal, AstStatGlobal, AstStatIndexName.
|
|
|
|
// With or without self
|
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
TypeId generalizedType = arena->addType(BlockedType{});
|
2022-06-17 02:05:14 +01:00
|
|
|
|
2023-02-17 23:41:51 +00:00
|
|
|
Checkpoint start = checkpoint(this);
|
2022-07-01 00:52:43 +01:00
|
|
|
FunctionSignature sig = checkFunctionSignature(scope, function->func);
|
2022-06-03 23:15:45 +01:00
|
|
|
|
2022-06-17 02:05:14 +01:00
|
|
|
if (AstExprLocal* localName = function->name->as<AstExprLocal>())
|
2022-06-03 23:15:45 +01:00
|
|
|
{
|
2022-06-17 02:05:14 +01:00
|
|
|
std::optional<TypeId> existingFunctionTy = scope->lookup(localName->local);
|
|
|
|
if (existingFunctionTy)
|
|
|
|
{
|
2022-12-02 18:09:59 +00:00
|
|
|
addConstraint(scope, function->name->location, SubtypeConstraint{generalizedType, *existingFunctionTy});
|
|
|
|
|
|
|
|
Symbol sym{localName->local};
|
|
|
|
std::optional<DefId> def = dfg->getDef(sym);
|
|
|
|
LUAU_ASSERT(def);
|
|
|
|
scope->bindings[sym].typeId = generalizedType;
|
|
|
|
scope->dcrRefinements[*def] = generalizedType;
|
2022-06-17 02:05:14 +01:00
|
|
|
}
|
|
|
|
else
|
2022-12-02 18:09:59 +00:00
|
|
|
scope->bindings[localName->local] = Binding{generalizedType, localName->location};
|
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
sig.bodyScope->bindings[localName->local] = Binding{sig.signature, localName->location};
|
2022-06-17 02:05:14 +01:00
|
|
|
}
|
|
|
|
else if (AstExprGlobal* globalName = function->name->as<AstExprGlobal>())
|
|
|
|
{
|
|
|
|
std::optional<TypeId> existingFunctionTy = scope->lookup(globalName->name);
|
2022-12-02 18:09:59 +00:00
|
|
|
if (!existingFunctionTy)
|
|
|
|
ice->ice("prepopulateGlobalScope did not populate a global name", globalName->location);
|
|
|
|
|
|
|
|
generalizedType = *existingFunctionTy;
|
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
sig.bodyScope->bindings[globalName->name] = Binding{sig.signature, globalName->location};
|
2022-06-17 02:05:14 +01:00
|
|
|
}
|
|
|
|
else if (AstExprIndexName* indexName = function->name->as<AstExprIndexName>())
|
|
|
|
{
|
2023-02-10 19:40:38 +00:00
|
|
|
TypeId lvalueType = checkLValue(scope, indexName);
|
|
|
|
// TODO figure out how to populate the location field of the table Property.
|
|
|
|
addConstraint(scope, indexName->location, SubtypeConstraint{lvalueType, generalizedType});
|
2022-07-01 00:52:43 +01:00
|
|
|
}
|
|
|
|
else if (AstExprError* err = function->name->as<AstExprError>())
|
|
|
|
{
|
2023-01-04 20:53:17 +00:00
|
|
|
generalizedType = builtinTypes->errorRecoveryType();
|
2022-06-03 23:15:45 +01:00
|
|
|
}
|
|
|
|
|
2022-12-02 18:09:59 +00:00
|
|
|
if (generalizedType == nullptr)
|
|
|
|
ice->ice("generalizedType == nullptr", function->location);
|
2022-06-03 23:15:45 +01:00
|
|
|
|
2022-07-01 00:52:43 +01:00
|
|
|
checkFunctionBody(sig.bodyScope, function->func);
|
2022-12-02 18:09:59 +00:00
|
|
|
Checkpoint end = checkpoint(this);
|
2022-07-01 00:52:43 +01:00
|
|
|
|
2022-08-18 22:32:08 +01:00
|
|
|
NotNull<Scope> constraintScope{sig.signatureScope ? sig.signatureScope.get() : sig.bodyScope.get()};
|
2022-09-02 00:14:03 +01:00
|
|
|
std::unique_ptr<Constraint> c =
|
2022-12-02 18:09:59 +00:00
|
|
|
std::make_unique<Constraint>(constraintScope, function->name->location, GeneralizationConstraint{generalizedType, sig.signature});
|
2022-11-10 22:53:13 +00:00
|
|
|
|
|
|
|
forEachConstraint(start, end, this, [&c](const ConstraintPtr& constraint) {
|
|
|
|
c->dependencies.push_back(NotNull{constraint.get()});
|
|
|
|
});
|
2022-06-03 23:15:45 +01:00
|
|
|
|
|
|
|
addConstraint(scope, std::move(c));
|
|
|
|
}
|
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatReturn* ret)
|
2022-06-03 23:15:45 +01:00
|
|
|
{
|
2022-09-23 20:17:25 +01:00
|
|
|
// At this point, the only way scope->returnType should have anything
|
|
|
|
// interesting in it is if the function has an explicit return annotation.
|
|
|
|
// If this is the case, then we can expect that the return expression
|
|
|
|
// conforms to that.
|
2023-02-17 23:41:51 +00:00
|
|
|
std::vector<std::optional<TypeId>> expectedTypes;
|
2022-09-23 20:17:25 +01:00
|
|
|
for (TypeId ty : scope->returnType)
|
|
|
|
expectedTypes.push_back(ty);
|
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
TypePackId exprTypes = checkPack(scope, ret->list, expectedTypes).tp;
|
2022-09-02 00:14:03 +01:00
|
|
|
addConstraint(scope, ret->location, PackSubtypeConstraint{exprTypes, scope->returnType});
|
2022-06-03 23:15:45 +01:00
|
|
|
}
|
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatBlock* block)
|
2022-06-03 23:15:45 +01:00
|
|
|
{
|
2022-08-18 22:32:08 +01:00
|
|
|
ScopePtr innerScope = childScope(block, scope);
|
2022-06-03 23:15:45 +01:00
|
|
|
|
2022-07-01 00:52:43 +01:00
|
|
|
visitBlockWithoutChildScope(innerScope, block);
|
2022-06-03 23:15:45 +01:00
|
|
|
}
|
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatAssign* assign)
|
2022-06-17 02:05:14 +01:00
|
|
|
{
|
2022-10-21 18:54:01 +01:00
|
|
|
TypePackId varPackId = checkLValues(scope, assign->vars);
|
2022-12-02 18:09:59 +00:00
|
|
|
|
2023-02-17 23:41:51 +00:00
|
|
|
TypePack expectedPack = extendTypePack(*arena, builtinTypes, varPackId, assign->values.size);
|
|
|
|
|
|
|
|
std::vector<std::optional<TypeId>> expectedTypes;
|
|
|
|
expectedTypes.reserve(expectedPack.head.size());
|
|
|
|
|
|
|
|
for (TypeId ty : expectedPack.head)
|
|
|
|
{
|
|
|
|
ty = follow(ty);
|
|
|
|
if (get<FreeType>(ty))
|
|
|
|
expectedTypes.push_back(std::nullopt);
|
|
|
|
else
|
|
|
|
expectedTypes.push_back(ty);
|
|
|
|
}
|
|
|
|
|
|
|
|
TypePackId valuePack = checkPack(scope, assign->values, expectedTypes).tp;
|
2022-06-17 02:05:14 +01:00
|
|
|
|
2022-09-02 00:14:03 +01:00
|
|
|
addConstraint(scope, assign->location, PackSubtypeConstraint{valuePack, varPackId});
|
2022-06-17 02:05:14 +01:00
|
|
|
}
|
|
|
|
|
2022-08-18 22:32:08 +01:00
|
|
|
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatCompoundAssign* assign)
|
|
|
|
{
|
2023-01-06 21:14:35 +00:00
|
|
|
// We need to tweak the BinaryConstraint that we emit, so we cannot use the
|
|
|
|
// strategy of falsifying an AST fragment.
|
|
|
|
TypeId varId = checkLValue(scope, assign->var);
|
|
|
|
Inference valueInf = check(scope, assign->value);
|
2022-08-18 22:32:08 +01:00
|
|
|
|
2023-01-06 21:14:35 +00:00
|
|
|
TypeId resultType = arena->addType(BlockedType{});
|
|
|
|
addConstraint(scope, assign->location,
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
BinaryConstraint{assign->op, varId, valueInf.ty, resultType, assign, &module->astOriginalCallTypes, &module->astOverloadResolvedTypes});
|
2023-01-06 21:14:35 +00:00
|
|
|
addConstraint(scope, assign->location, SubtypeConstraint{resultType, varId});
|
2022-08-18 22:32:08 +01:00
|
|
|
}
|
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatIf* ifStatement)
|
2022-06-17 02:05:14 +01:00
|
|
|
{
|
2022-10-21 18:54:01 +01:00
|
|
|
ScopePtr condScope = childScope(ifStatement->condition, scope);
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
auto [_, refinement] = check(condScope, ifStatement->condition, std::nullopt);
|
2022-06-17 02:05:14 +01:00
|
|
|
|
2022-08-18 22:32:08 +01:00
|
|
|
ScopePtr thenScope = childScope(ifStatement->thenbody, scope);
|
2023-02-10 19:40:38 +00:00
|
|
|
applyRefinements(thenScope, ifStatement->condition->location, refinement);
|
2022-06-17 02:05:14 +01:00
|
|
|
visit(thenScope, ifStatement->thenbody);
|
|
|
|
|
|
|
|
if (ifStatement->elsebody)
|
|
|
|
{
|
2022-08-18 22:32:08 +01:00
|
|
|
ScopePtr elseScope = childScope(ifStatement->elsebody, scope);
|
2023-02-10 19:40:38 +00:00
|
|
|
applyRefinements(elseScope, ifStatement->elseLocation.value_or(ifStatement->condition->location), refinementArena.negation(refinement));
|
2022-06-17 02:05:14 +01:00
|
|
|
visit(elseScope, ifStatement->elsebody);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-17 23:41:51 +00:00
|
|
|
static bool occursCheck(TypeId needle, TypeId haystack)
|
|
|
|
{
|
|
|
|
LUAU_ASSERT(get<BlockedType>(needle));
|
|
|
|
haystack = follow(haystack);
|
|
|
|
|
|
|
|
auto checkHaystack = [needle](TypeId haystack) {
|
|
|
|
return occursCheck(needle, haystack);
|
|
|
|
};
|
|
|
|
|
|
|
|
if (needle == haystack)
|
|
|
|
return true;
|
|
|
|
else if (auto ut = get<UnionType>(haystack))
|
|
|
|
return std::any_of(begin(ut), end(ut), checkHaystack);
|
|
|
|
else if (auto it = get<IntersectionType>(haystack))
|
|
|
|
return std::any_of(begin(it), end(it), checkHaystack);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatTypeAlias* alias)
|
2022-06-24 02:56:00 +01:00
|
|
|
{
|
2023-02-17 23:41:51 +00:00
|
|
|
ScopePtr* defnScope = astTypeAliasDefiningScopes.find(alias);
|
|
|
|
|
|
|
|
std::unordered_map<Name, TypeFun>* typeBindings;
|
|
|
|
if (alias->exported)
|
|
|
|
typeBindings = &scope->exportedTypeBindings;
|
|
|
|
else
|
|
|
|
typeBindings = &scope->privateTypeBindings;
|
|
|
|
|
2022-08-04 23:35:33 +01:00
|
|
|
// These will be undefined if the alias was a duplicate definition, in which
|
|
|
|
// case we just skip over it.
|
2023-02-17 23:41:51 +00:00
|
|
|
auto bindingIt = typeBindings->find(alias->name.value);
|
|
|
|
if (bindingIt == typeBindings->end() || defnScope == nullptr)
|
2022-08-04 23:35:33 +01:00
|
|
|
return;
|
2022-06-24 02:56:00 +01:00
|
|
|
|
2023-02-17 23:41:51 +00:00
|
|
|
TypeId ty = resolveType(*defnScope, alias->type, /* inTypeArguments */ false);
|
2022-08-04 23:35:33 +01:00
|
|
|
|
2023-02-17 23:41:51 +00:00
|
|
|
TypeId aliasTy = bindingIt->second.type;
|
|
|
|
LUAU_ASSERT(get<BlockedType>(aliasTy));
|
|
|
|
|
|
|
|
if (occursCheck(aliasTy, ty))
|
2022-09-02 00:14:03 +01:00
|
|
|
{
|
2023-02-17 23:41:51 +00:00
|
|
|
asMutable(aliasTy)->ty.emplace<BoundType>(builtinTypes->anyType);
|
|
|
|
reportError(alias->nameLocation, OccursCheckFailed{});
|
2022-09-02 00:14:03 +01:00
|
|
|
}
|
2023-02-17 23:41:51 +00:00
|
|
|
else
|
|
|
|
asMutable(aliasTy)->ty.emplace<BoundType>(ty);
|
|
|
|
|
|
|
|
std::vector<TypeId> typeParams;
|
|
|
|
for (auto tyParam : createGenerics(*defnScope, alias->generics, /* useCache */ true))
|
|
|
|
typeParams.push_back(tyParam.second.ty);
|
|
|
|
|
|
|
|
std::vector<TypePackId> typePackParams;
|
|
|
|
for (auto tpParam : createGenericPacks(*defnScope, alias->genericPacks, /* useCache */ true))
|
|
|
|
typePackParams.push_back(tpParam.second.tp);
|
|
|
|
|
|
|
|
addConstraint(scope, alias->type->location,
|
|
|
|
NameConstraint{
|
|
|
|
ty,
|
|
|
|
alias->name.value,
|
|
|
|
/*synthetic=*/false,
|
|
|
|
std::move(typeParams),
|
|
|
|
std::move(typePackParams),
|
|
|
|
});
|
2022-06-24 02:56:00 +01:00
|
|
|
}
|
|
|
|
|
2022-08-04 23:35:33 +01:00
|
|
|
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatDeclareGlobal* global)
|
|
|
|
{
|
|
|
|
LUAU_ASSERT(global->type);
|
|
|
|
|
2023-01-20 20:27:03 +00:00
|
|
|
TypeId globalTy = resolveType(scope, global->type, /* inTypeArguments */ false);
|
2022-08-11 22:01:33 +01:00
|
|
|
Name globalName(global->name.value);
|
|
|
|
|
|
|
|
module->declaredGlobals[globalName] = globalTy;
|
2022-08-04 23:35:33 +01:00
|
|
|
scope->bindings[global->name] = Binding{globalTy, global->location};
|
|
|
|
}
|
|
|
|
|
2022-08-11 22:01:33 +01:00
|
|
|
static bool isMetamethod(const Name& name)
|
|
|
|
{
|
|
|
|
return name == "__index" || name == "__newindex" || name == "__call" || name == "__concat" || name == "__unm" || name == "__add" ||
|
|
|
|
name == "__sub" || name == "__mul" || name == "__div" || name == "__mod" || name == "__pow" || name == "__tostring" ||
|
|
|
|
name == "__metatable" || name == "__eq" || name == "__lt" || name == "__le" || name == "__mode" || name == "__iter" || name == "__len";
|
|
|
|
}
|
|
|
|
|
|
|
|
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatDeclareClass* declaredClass)
|
2022-08-04 23:35:33 +01:00
|
|
|
{
|
2023-01-04 20:53:17 +00:00
|
|
|
std::optional<TypeId> superTy = FFlag::LuauNegatedClassTypes ? std::make_optional(builtinTypes->classType) : std::nullopt;
|
2022-08-11 22:01:33 +01:00
|
|
|
if (declaredClass->superName)
|
|
|
|
{
|
|
|
|
Name superName = Name(declaredClass->superName->value);
|
|
|
|
std::optional<TypeFun> lookupType = scope->lookupType(superName);
|
|
|
|
|
|
|
|
if (!lookupType)
|
|
|
|
{
|
|
|
|
reportError(declaredClass->location, UnknownSymbol{superName, UnknownSymbol::Type});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We don't have generic classes, so this assertion _should_ never be hit.
|
|
|
|
LUAU_ASSERT(lookupType->typeParams.size() == 0 && lookupType->typePackParams.size() == 0);
|
|
|
|
superTy = lookupType->type;
|
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
if (!get<ClassType>(follow(*superTy)))
|
2022-08-11 22:01:33 +01:00
|
|
|
{
|
|
|
|
reportError(declaredClass->location,
|
|
|
|
GenericError{format("Cannot use non-class type '%s' as a superclass of class '%s'", superName.c_str(), declaredClass->name.value)});
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Name className(declaredClass->name.value);
|
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
TypeId classTy = arena->addType(ClassType(className, {}, superTy, std::nullopt, {}, {}, moduleName));
|
|
|
|
ClassType* ctv = getMutable<ClassType>(classTy);
|
2022-08-11 22:01:33 +01:00
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
TypeId metaTy = arena->addType(TableType{TableState::Sealed, scope->level, scope.get()});
|
|
|
|
TableType* metatable = getMutable<TableType>(metaTy);
|
2022-08-11 22:01:33 +01:00
|
|
|
|
|
|
|
ctv->metatable = metaTy;
|
|
|
|
|
|
|
|
scope->exportedTypeBindings[className] = TypeFun{{}, classTy};
|
|
|
|
|
|
|
|
for (const AstDeclaredClassProp& prop : declaredClass->props)
|
|
|
|
{
|
|
|
|
Name propName(prop.name.value);
|
2023-01-20 20:27:03 +00:00
|
|
|
TypeId propTy = resolveType(scope, prop.ty, /* inTypeArguments */ false);
|
2022-08-11 22:01:33 +01:00
|
|
|
|
|
|
|
bool assignToMetatable = isMetamethod(propName);
|
|
|
|
|
|
|
|
// Function types always take 'self', but this isn't reflected in the
|
|
|
|
// parsed annotation. Add it here.
|
|
|
|
if (prop.isMethod)
|
|
|
|
{
|
2023-01-04 20:53:17 +00:00
|
|
|
if (FunctionType* ftv = getMutable<FunctionType>(propTy))
|
2022-08-11 22:01:33 +01:00
|
|
|
{
|
|
|
|
ftv->argNames.insert(ftv->argNames.begin(), FunctionArgument{"self", {}});
|
|
|
|
ftv->argTypes = arena->addTypePack(TypePack{{classTy}, ftv->argTypes});
|
|
|
|
|
|
|
|
ftv->hasSelf = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctv->props.count(propName) == 0)
|
|
|
|
{
|
|
|
|
if (assignToMetatable)
|
|
|
|
metatable->props[propName] = {propTy};
|
|
|
|
else
|
|
|
|
ctv->props[propName] = {propTy};
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TypeId currentTy = assignToMetatable ? metatable->props[propName].type : ctv->props[propName].type;
|
|
|
|
|
|
|
|
// We special-case this logic to keep the intersection flat; otherwise we
|
|
|
|
// would create a ton of nested intersection types.
|
2023-01-04 20:53:17 +00:00
|
|
|
if (const IntersectionType* itv = get<IntersectionType>(currentTy))
|
2022-08-11 22:01:33 +01:00
|
|
|
{
|
|
|
|
std::vector<TypeId> options = itv->parts;
|
|
|
|
options.push_back(propTy);
|
2023-01-04 20:53:17 +00:00
|
|
|
TypeId newItv = arena->addType(IntersectionType{std::move(options)});
|
2022-08-11 22:01:33 +01:00
|
|
|
|
|
|
|
if (assignToMetatable)
|
|
|
|
metatable->props[propName] = {newItv};
|
|
|
|
else
|
|
|
|
ctv->props[propName] = {newItv};
|
|
|
|
}
|
2023-01-04 20:53:17 +00:00
|
|
|
else if (get<FunctionType>(currentTy))
|
2022-08-11 22:01:33 +01:00
|
|
|
{
|
2023-01-04 20:53:17 +00:00
|
|
|
TypeId intersection = arena->addType(IntersectionType{{currentTy, propTy}});
|
2022-08-11 22:01:33 +01:00
|
|
|
|
|
|
|
if (assignToMetatable)
|
|
|
|
metatable->props[propName] = {intersection};
|
|
|
|
else
|
|
|
|
ctv->props[propName] = {intersection};
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
reportError(declaredClass->location, GenericError{format("Cannot overload non-function class member '%s'", propName.c_str())});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-08-04 23:35:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatDeclareFunction* global)
|
|
|
|
{
|
2022-08-11 22:01:33 +01:00
|
|
|
std::vector<std::pair<Name, GenericTypeDefinition>> generics = createGenerics(scope, global->generics);
|
|
|
|
std::vector<std::pair<Name, GenericTypePackDefinition>> genericPacks = createGenericPacks(scope, global->genericPacks);
|
|
|
|
|
|
|
|
std::vector<TypeId> genericTys;
|
|
|
|
genericTys.reserve(generics.size());
|
|
|
|
for (auto& [name, generic] : generics)
|
2022-09-08 23:14:25 +01:00
|
|
|
{
|
2022-08-11 22:01:33 +01:00
|
|
|
genericTys.push_back(generic.ty);
|
2022-09-08 23:14:25 +01:00
|
|
|
scope->privateTypeBindings[name] = TypeFun{generic.ty};
|
|
|
|
}
|
2022-08-11 22:01:33 +01:00
|
|
|
|
|
|
|
std::vector<TypePackId> genericTps;
|
|
|
|
genericTps.reserve(genericPacks.size());
|
|
|
|
for (auto& [name, generic] : genericPacks)
|
2022-09-08 23:14:25 +01:00
|
|
|
{
|
2022-08-11 22:01:33 +01:00
|
|
|
genericTps.push_back(generic.tp);
|
2022-09-08 23:14:25 +01:00
|
|
|
scope->privateTypePackBindings[name] = generic.tp;
|
|
|
|
}
|
2022-08-11 22:01:33 +01:00
|
|
|
|
|
|
|
ScopePtr funScope = scope;
|
|
|
|
if (!generics.empty() || !genericPacks.empty())
|
2022-08-18 22:32:08 +01:00
|
|
|
funScope = childScope(global, scope);
|
2022-08-11 22:01:33 +01:00
|
|
|
|
2023-01-20 20:27:03 +00:00
|
|
|
TypePackId paramPack = resolveTypePack(funScope, global->params, /* inTypeArguments */ false);
|
|
|
|
TypePackId retPack = resolveTypePack(funScope, global->retTypes, /* inTypeArguments */ false);
|
2023-01-04 20:53:17 +00:00
|
|
|
TypeId fnType = arena->addType(FunctionType{TypeLevel{}, funScope.get(), std::move(genericTys), std::move(genericTps), paramPack, retPack});
|
|
|
|
FunctionType* ftv = getMutable<FunctionType>(fnType);
|
2022-08-11 22:01:33 +01:00
|
|
|
|
|
|
|
ftv->argNames.reserve(global->paramNames.size);
|
|
|
|
for (const auto& el : global->paramNames)
|
|
|
|
ftv->argNames.push_back(FunctionArgument{el.first.value, el.second});
|
|
|
|
|
|
|
|
Name fnName(global->name.value);
|
|
|
|
|
|
|
|
module->declaredGlobals[fnName] = fnType;
|
|
|
|
scope->bindings[global->name] = Binding{fnType, global->location};
|
2022-08-04 23:35:33 +01:00
|
|
|
}
|
|
|
|
|
2022-09-29 23:23:10 +01:00
|
|
|
void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatError* error)
|
|
|
|
{
|
|
|
|
for (AstStat* stat : error->statements)
|
|
|
|
visit(scope, stat);
|
|
|
|
for (AstExpr* expr : error->expressions)
|
|
|
|
check(scope, expr);
|
|
|
|
}
|
|
|
|
|
2023-02-17 23:41:51 +00:00
|
|
|
InferencePack ConstraintGraphBuilder::checkPack(
|
|
|
|
const ScopePtr& scope, AstArray<AstExpr*> exprs, const std::vector<std::optional<TypeId>>& expectedTypes)
|
2022-06-03 23:15:45 +01:00
|
|
|
{
|
2022-09-02 00:14:03 +01:00
|
|
|
std::vector<TypeId> head;
|
|
|
|
std::optional<TypePackId> tail;
|
2022-06-17 02:05:14 +01:00
|
|
|
|
|
|
|
for (size_t i = 0; i < exprs.size; ++i)
|
|
|
|
{
|
|
|
|
AstExpr* expr = exprs.data[i];
|
|
|
|
if (i < exprs.size - 1)
|
2022-09-23 20:17:25 +01:00
|
|
|
{
|
|
|
|
std::optional<TypeId> expectedType;
|
|
|
|
if (i < expectedTypes.size())
|
|
|
|
expectedType = expectedTypes[i];
|
2023-02-17 23:41:51 +00:00
|
|
|
head.push_back(check(scope, expr, expectedType).ty);
|
2022-09-23 20:17:25 +01:00
|
|
|
}
|
2022-06-17 02:05:14 +01:00
|
|
|
else
|
2022-09-23 20:17:25 +01:00
|
|
|
{
|
2023-02-17 23:41:51 +00:00
|
|
|
std::vector<std::optional<TypeId>> expectedTailTypes;
|
2022-09-29 23:23:10 +01:00
|
|
|
if (i < expectedTypes.size())
|
|
|
|
expectedTailTypes.assign(begin(expectedTypes) + i, end(expectedTypes));
|
2022-10-28 11:37:29 +01:00
|
|
|
tail = checkPack(scope, expr, expectedTailTypes).tp;
|
2022-09-23 20:17:25 +01:00
|
|
|
}
|
2022-06-17 02:05:14 +01:00
|
|
|
}
|
|
|
|
|
2022-09-02 00:14:03 +01:00
|
|
|
if (head.empty() && tail)
|
2022-10-28 11:37:29 +01:00
|
|
|
return InferencePack{*tail};
|
2022-06-17 02:05:14 +01:00
|
|
|
else
|
2022-10-28 11:37:29 +01:00
|
|
|
return InferencePack{arena->addTypePack(TypePack{std::move(head), tail})};
|
2022-06-17 02:05:14 +01:00
|
|
|
}
|
|
|
|
|
2023-02-17 23:41:51 +00:00
|
|
|
InferencePack ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExpr* expr, const std::vector<std::optional<TypeId>>& expectedTypes)
|
2022-06-03 23:15:45 +01:00
|
|
|
{
|
2022-07-01 00:52:43 +01:00
|
|
|
RecursionCounter counter{&recursionCount};
|
|
|
|
|
|
|
|
if (recursionCount >= FInt::LuauCheckRecursionLimit)
|
|
|
|
{
|
|
|
|
reportCodeTooComplex(expr->location);
|
2023-01-04 20:53:17 +00:00
|
|
|
return InferencePack{builtinTypes->errorRecoveryTypePack()};
|
2022-07-01 00:52:43 +01:00
|
|
|
}
|
2022-06-03 23:15:45 +01:00
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
InferencePack result;
|
2022-06-17 02:05:14 +01:00
|
|
|
|
|
|
|
if (AstExprCall* call = expr->as<AstExprCall>())
|
2023-02-17 23:41:51 +00:00
|
|
|
result = checkPack(scope, call);
|
2022-07-01 00:52:43 +01:00
|
|
|
else if (AstExprVarargs* varargs = expr->as<AstExprVarargs>())
|
|
|
|
{
|
|
|
|
if (scope->varargPack)
|
2022-10-28 11:37:29 +01:00
|
|
|
result = InferencePack{*scope->varargPack};
|
2022-07-01 00:52:43 +01:00
|
|
|
else
|
2023-01-04 20:53:17 +00:00
|
|
|
result = InferencePack{builtinTypes->errorRecoveryTypePack()};
|
2022-07-01 00:52:43 +01:00
|
|
|
}
|
2022-06-17 02:05:14 +01:00
|
|
|
else
|
|
|
|
{
|
2022-09-23 20:17:25 +01:00
|
|
|
std::optional<TypeId> expectedType;
|
|
|
|
if (!expectedTypes.empty())
|
|
|
|
expectedType = expectedTypes[0];
|
2022-10-28 11:37:29 +01:00
|
|
|
TypeId t = check(scope, expr, expectedType).ty;
|
|
|
|
result = InferencePack{arena->addTypePack({t})};
|
2022-06-17 02:05:14 +01:00
|
|
|
}
|
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
LUAU_ASSERT(result.tp);
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
module->astTypePacks[expr] = result.tp;
|
2022-06-17 02:05:14 +01:00
|
|
|
return result;
|
2022-06-03 23:15:45 +01:00
|
|
|
}
|
|
|
|
|
2023-02-17 23:41:51 +00:00
|
|
|
InferencePack ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExprCall* call)
|
2022-06-03 23:15:45 +01:00
|
|
|
{
|
2022-12-02 18:09:59 +00:00
|
|
|
std::vector<AstExpr*> exprArgs;
|
2023-02-10 19:40:38 +00:00
|
|
|
|
|
|
|
std::vector<RefinementId> returnRefinements;
|
|
|
|
std::vector<std::optional<TypeId>> discriminantTypes;
|
|
|
|
|
2022-12-02 18:09:59 +00:00
|
|
|
if (call->self)
|
|
|
|
{
|
|
|
|
AstExprIndexName* indexExpr = call->func->as<AstExprIndexName>();
|
|
|
|
if (!indexExpr)
|
|
|
|
ice->ice("method call expression has no 'self'");
|
|
|
|
|
|
|
|
exprArgs.push_back(indexExpr->expr);
|
2023-02-10 19:40:38 +00:00
|
|
|
|
|
|
|
if (auto def = dfg->getDef(indexExpr->expr))
|
|
|
|
{
|
|
|
|
TypeId discriminantTy = arena->addType(BlockedType{});
|
|
|
|
returnRefinements.push_back(refinementArena.proposition(*def, discriminantTy));
|
|
|
|
discriminantTypes.push_back(discriminantTy);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
discriminantTypes.push_back(std::nullopt);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (AstExpr* arg : call->args)
|
|
|
|
{
|
|
|
|
exprArgs.push_back(arg);
|
|
|
|
|
|
|
|
if (auto def = dfg->getDef(arg))
|
|
|
|
{
|
|
|
|
TypeId discriminantTy = arena->addType(BlockedType{});
|
|
|
|
returnRefinements.push_back(refinementArena.proposition(*def, discriminantTy));
|
|
|
|
discriminantTypes.push_back(discriminantTy);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
discriminantTypes.push_back(std::nullopt);
|
2022-12-02 18:09:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Checkpoint startCheckpoint = checkpoint(this);
|
2022-10-28 11:37:29 +01:00
|
|
|
TypeId fnType = check(scope, call->func).ty;
|
2022-12-02 18:09:59 +00:00
|
|
|
Checkpoint fnEndCheckpoint = checkpoint(this);
|
2022-07-01 00:52:43 +01:00
|
|
|
|
2023-02-10 19:40:38 +00:00
|
|
|
module->astOriginalCallTypes[call->func] = fnType;
|
|
|
|
|
2022-12-02 18:09:59 +00:00
|
|
|
TypePackId expectedArgPack = arena->freshTypePack(scope.get());
|
|
|
|
TypePackId expectedRetPack = arena->freshTypePack(scope.get());
|
2023-01-04 20:53:17 +00:00
|
|
|
TypeId expectedFunctionType = arena->addType(FunctionType{expectedArgPack, expectedRetPack});
|
2022-12-02 18:09:59 +00:00
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
TypeId instantiatedFnType = arena->addType(BlockedType{});
|
2022-12-02 18:09:59 +00:00
|
|
|
addConstraint(scope, call->location, InstantiationConstraint{instantiatedFnType, fnType});
|
|
|
|
|
|
|
|
NotNull<Constraint> extractArgsConstraint = addConstraint(scope, call->location, SubtypeConstraint{instantiatedFnType, expectedFunctionType});
|
|
|
|
|
|
|
|
// Fully solve fnType, then extract its argument list as expectedArgPack.
|
|
|
|
forEachConstraint(startCheckpoint, fnEndCheckpoint, this, [extractArgsConstraint](const ConstraintPtr& constraint) {
|
|
|
|
extractArgsConstraint->dependencies.emplace_back(constraint.get());
|
|
|
|
});
|
|
|
|
|
|
|
|
const AstExpr* lastArg = exprArgs.size() ? exprArgs[exprArgs.size() - 1] : nullptr;
|
|
|
|
const bool needTail = lastArg && (lastArg->is<AstExprCall>() || lastArg->is<AstExprVarargs>());
|
|
|
|
|
|
|
|
TypePack expectedArgs;
|
|
|
|
|
|
|
|
if (!needTail)
|
2023-01-04 20:53:17 +00:00
|
|
|
expectedArgs = extendTypePack(*arena, builtinTypes, expectedArgPack, exprArgs.size());
|
2022-12-02 18:09:59 +00:00
|
|
|
else
|
2023-01-04 20:53:17 +00:00
|
|
|
expectedArgs = extendTypePack(*arena, builtinTypes, expectedArgPack, exprArgs.size() - 1);
|
2022-10-28 11:37:29 +01:00
|
|
|
|
2022-12-02 18:09:59 +00:00
|
|
|
std::vector<TypeId> args;
|
|
|
|
std::optional<TypePackId> argTail;
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
std::vector<RefinementId> argumentRefinements;
|
2022-11-18 19:47:21 +00:00
|
|
|
|
2022-12-02 18:09:59 +00:00
|
|
|
Checkpoint argCheckpoint = checkpoint(this);
|
2022-11-18 19:47:21 +00:00
|
|
|
|
2022-12-02 18:09:59 +00:00
|
|
|
for (size_t i = 0; i < exprArgs.size(); ++i)
|
|
|
|
{
|
|
|
|
AstExpr* arg = exprArgs[i];
|
|
|
|
std::optional<TypeId> expectedType;
|
|
|
|
if (i < expectedArgs.head.size())
|
|
|
|
expectedType = expectedArgs.head[i];
|
|
|
|
|
|
|
|
if (i == 0 && call->self)
|
|
|
|
{
|
|
|
|
// The self type has already been computed as a side effect of
|
|
|
|
// computing fnType. If computing that did not cause us to exceed a
|
|
|
|
// recursion limit, we can fetch it from astTypes rather than
|
|
|
|
// recomputing it.
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
TypeId* selfTy = module->astTypes.find(exprArgs[0]);
|
2022-12-02 18:09:59 +00:00
|
|
|
if (selfTy)
|
|
|
|
args.push_back(*selfTy);
|
|
|
|
else
|
|
|
|
args.push_back(arena->freshType(scope.get()));
|
|
|
|
}
|
|
|
|
else if (i < exprArgs.size() - 1 || !(arg->is<AstExprCall>() || arg->is<AstExprVarargs>()))
|
2022-12-09 19:57:01 +00:00
|
|
|
{
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
auto [ty, refinement] = check(scope, arg, expectedType);
|
2022-12-09 19:57:01 +00:00
|
|
|
args.push_back(ty);
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
argumentRefinements.push_back(refinement);
|
2022-12-09 19:57:01 +00:00
|
|
|
}
|
2022-12-02 18:09:59 +00:00
|
|
|
else
|
2023-02-10 19:40:38 +00:00
|
|
|
{
|
2023-02-17 23:41:51 +00:00
|
|
|
auto [tp, refis] = checkPack(scope, arg, {});
|
2023-02-10 19:40:38 +00:00
|
|
|
argTail = tp;
|
|
|
|
argumentRefinements.insert(argumentRefinements.end(), refis.begin(), refis.end());
|
|
|
|
}
|
2022-11-18 19:47:21 +00:00
|
|
|
}
|
2022-06-17 02:05:14 +01:00
|
|
|
|
2022-12-02 18:09:59 +00:00
|
|
|
Checkpoint argEndCheckpoint = checkpoint(this);
|
|
|
|
|
|
|
|
// Do not solve argument constraints until after we have extracted the
|
|
|
|
// expected types from the callable.
|
|
|
|
forEachConstraint(argCheckpoint, argEndCheckpoint, this, [extractArgsConstraint](const ConstraintPtr& constraint) {
|
|
|
|
constraint->dependencies.push_back(extractArgsConstraint);
|
|
|
|
});
|
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
if (matchSetmetatable(*call))
|
2022-09-23 20:17:25 +01:00
|
|
|
{
|
2022-12-02 18:09:59 +00:00
|
|
|
TypePack argTailPack;
|
|
|
|
if (argTail && args.size() < 2)
|
2023-01-04 20:53:17 +00:00
|
|
|
argTailPack = extendTypePack(*arena, builtinTypes, *argTail, 2 - args.size());
|
2022-12-02 18:09:59 +00:00
|
|
|
|
|
|
|
LUAU_ASSERT(args.size() + argTailPack.head.size() == 2);
|
|
|
|
|
|
|
|
TypeId target = args.size() > 0 ? args[0] : argTailPack.head[0];
|
|
|
|
TypeId mt = args.size() > 1 ? args[1] : argTailPack.head[args.size() == 0 ? 1 : 0];
|
2022-10-28 11:37:29 +01:00
|
|
|
|
|
|
|
AstExpr* targetExpr = call->args.data[0];
|
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
MetatableType mtv{target, mt};
|
2022-10-28 11:37:29 +01:00
|
|
|
TypeId resultTy = arena->addType(mtv);
|
|
|
|
|
|
|
|
if (AstExprLocal* targetLocal = targetExpr->as<AstExprLocal>())
|
2023-01-27 22:28:31 +00:00
|
|
|
{
|
2022-10-28 11:37:29 +01:00
|
|
|
scope->bindings[targetLocal->local].typeId = resultTy;
|
2023-01-27 22:28:31 +00:00
|
|
|
auto def = dfg->getDef(targetLocal->local);
|
|
|
|
if (def)
|
|
|
|
scope->dcrRefinements[*def] = resultTy; // TODO: typestates: track this as an assignment
|
|
|
|
}
|
|
|
|
|
2023-02-10 19:40:38 +00:00
|
|
|
return InferencePack{arena->addTypePack({resultTy}), {refinementArena.variadic(returnRefinements)}};
|
2022-09-23 20:17:25 +01:00
|
|
|
}
|
2022-10-28 11:37:29 +01:00
|
|
|
else
|
2022-09-23 20:17:25 +01:00
|
|
|
{
|
2023-02-10 19:40:38 +00:00
|
|
|
if (matchAssert(*call) && !argumentRefinements.empty())
|
|
|
|
applyRefinements(scope, call->args.data[0]->location, argumentRefinements[0]);
|
2022-10-28 11:37:29 +01:00
|
|
|
|
|
|
|
// TODO: How do expectedTypes play into this? Do they?
|
|
|
|
TypePackId rets = arena->addTypePack(BlockedTypePack{});
|
2022-12-02 18:09:59 +00:00
|
|
|
TypePackId argPack = arena->addTypePack(TypePack{args, argTail});
|
2023-01-04 20:53:17 +00:00
|
|
|
FunctionType ftv(TypeLevel{}, scope.get(), argPack, rets);
|
2022-10-28 11:37:29 +01:00
|
|
|
|
2022-12-02 18:09:59 +00:00
|
|
|
NotNull<Constraint> fcc = addConstraint(scope, call->func->location,
|
2022-10-28 11:37:29 +01:00
|
|
|
FunctionCallConstraint{
|
|
|
|
fnType,
|
|
|
|
argPack,
|
|
|
|
rets,
|
|
|
|
call,
|
2023-02-10 19:40:38 +00:00
|
|
|
std::move(discriminantTypes),
|
2022-10-28 11:37:29 +01:00
|
|
|
});
|
|
|
|
|
2022-12-02 18:09:59 +00:00
|
|
|
// We force constraints produced by checking function arguments to wait
|
|
|
|
// until after we have resolved the constraint on the function itself.
|
|
|
|
// This ensures, for instance, that we start inferring the contents of
|
|
|
|
// lambdas under the assumption that their arguments and return types
|
|
|
|
// will be compatible with the enclosing function call.
|
|
|
|
forEachConstraint(fnEndCheckpoint, argEndCheckpoint, this, [fcc](const ConstraintPtr& constraint) {
|
|
|
|
fcc->dependencies.emplace_back(constraint.get());
|
|
|
|
});
|
|
|
|
|
2023-02-10 19:40:38 +00:00
|
|
|
return InferencePack{rets, {refinementArena.variadic(returnRefinements)}};
|
2022-09-23 20:17:25 +01:00
|
|
|
}
|
2022-10-28 11:37:29 +01:00
|
|
|
}
|
|
|
|
|
2022-11-04 17:33:22 +00:00
|
|
|
Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExpr* expr, std::optional<TypeId> expectedType, bool forceSingleton)
|
2022-10-28 11:37:29 +01:00
|
|
|
{
|
|
|
|
RecursionCounter counter{&recursionCount};
|
|
|
|
|
|
|
|
if (recursionCount >= FInt::LuauCheckRecursionLimit)
|
|
|
|
{
|
|
|
|
reportCodeTooComplex(expr->location);
|
2023-01-04 20:53:17 +00:00
|
|
|
return Inference{builtinTypes->errorRecoveryType()};
|
2022-10-28 11:37:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Inference result;
|
|
|
|
|
|
|
|
if (auto group = expr->as<AstExprGroup>())
|
2022-11-04 17:33:22 +00:00
|
|
|
result = check(scope, group->expr, expectedType, forceSingleton);
|
2022-10-28 11:37:29 +01:00
|
|
|
else if (auto stringExpr = expr->as<AstExprConstantString>())
|
2022-11-04 17:33:22 +00:00
|
|
|
result = check(scope, stringExpr, expectedType, forceSingleton);
|
2022-10-28 11:37:29 +01:00
|
|
|
else if (expr->is<AstExprConstantNumber>())
|
2023-01-04 20:53:17 +00:00
|
|
|
result = Inference{builtinTypes->numberType};
|
2022-10-28 11:37:29 +01:00
|
|
|
else if (auto boolExpr = expr->as<AstExprConstantBool>())
|
2022-11-04 17:33:22 +00:00
|
|
|
result = check(scope, boolExpr, expectedType, forceSingleton);
|
2022-06-17 02:05:14 +01:00
|
|
|
else if (expr->is<AstExprConstantNil>())
|
2023-01-04 20:53:17 +00:00
|
|
|
result = Inference{builtinTypes->nilType};
|
2022-10-21 18:54:01 +01:00
|
|
|
else if (auto local = expr->as<AstExprLocal>())
|
|
|
|
result = check(scope, local);
|
|
|
|
else if (auto global = expr->as<AstExprGlobal>())
|
|
|
|
result = check(scope, global);
|
2022-07-01 00:52:43 +01:00
|
|
|
else if (expr->is<AstExprVarargs>())
|
|
|
|
result = flattenPack(scope, expr->location, checkPack(scope, expr));
|
2022-10-28 11:37:29 +01:00
|
|
|
else if (auto call = expr->as<AstExprCall>())
|
2023-02-17 23:41:51 +00:00
|
|
|
result = flattenPack(scope, expr->location, checkPack(scope, call)); // TODO: needs predicates too
|
2022-06-17 02:05:14 +01:00
|
|
|
else if (auto a = expr->as<AstExprFunction>())
|
|
|
|
{
|
2022-12-02 18:09:59 +00:00
|
|
|
Checkpoint startCheckpoint = checkpoint(this);
|
|
|
|
FunctionSignature sig = checkFunctionSignature(scope, a, expectedType);
|
2022-07-01 00:52:43 +01:00
|
|
|
checkFunctionBody(sig.bodyScope, a);
|
2022-12-02 18:09:59 +00:00
|
|
|
Checkpoint endCheckpoint = checkpoint(this);
|
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
TypeId generalizedTy = arena->addType(BlockedType{});
|
2022-12-02 18:09:59 +00:00
|
|
|
NotNull<Constraint> gc = addConstraint(scope, expr->location, GeneralizationConstraint{generalizedTy, sig.signature});
|
|
|
|
|
|
|
|
forEachConstraint(startCheckpoint, endCheckpoint, this, [gc](const ConstraintPtr& constraint) {
|
|
|
|
gc->dependencies.emplace_back(constraint.get());
|
|
|
|
});
|
|
|
|
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
result = Inference{generalizedTy};
|
2022-06-17 02:05:14 +01:00
|
|
|
}
|
|
|
|
else if (auto indexName = expr->as<AstExprIndexName>())
|
|
|
|
result = check(scope, indexName);
|
2022-07-01 00:52:43 +01:00
|
|
|
else if (auto indexExpr = expr->as<AstExprIndexExpr>())
|
|
|
|
result = check(scope, indexExpr);
|
2022-06-17 02:05:14 +01:00
|
|
|
else if (auto table = expr->as<AstExprTable>())
|
2022-09-23 20:17:25 +01:00
|
|
|
result = check(scope, table, expectedType);
|
2022-07-01 00:52:43 +01:00
|
|
|
else if (auto unary = expr->as<AstExprUnary>())
|
|
|
|
result = check(scope, unary);
|
|
|
|
else if (auto binary = expr->as<AstExprBinary>())
|
2022-10-21 18:54:01 +01:00
|
|
|
result = check(scope, binary, expectedType);
|
2022-08-18 22:32:08 +01:00
|
|
|
else if (auto ifElse = expr->as<AstExprIfElse>())
|
2022-09-23 20:17:25 +01:00
|
|
|
result = check(scope, ifElse, expectedType);
|
2022-08-11 22:01:33 +01:00
|
|
|
else if (auto typeAssert = expr->as<AstExprTypeAssertion>())
|
|
|
|
result = check(scope, typeAssert);
|
2023-01-27 22:28:31 +00:00
|
|
|
else if (auto interpString = expr->as<AstExprInterpString>())
|
|
|
|
result = check(scope, interpString);
|
2022-07-01 00:52:43 +01:00
|
|
|
else if (auto err = expr->as<AstExprError>())
|
|
|
|
{
|
|
|
|
// Open question: Should we traverse into this?
|
2022-09-29 23:23:10 +01:00
|
|
|
for (AstExpr* subExpr : err->expressions)
|
|
|
|
check(scope, subExpr);
|
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
result = Inference{builtinTypes->errorRecoveryType()};
|
2022-06-17 02:05:14 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LUAU_ASSERT(0);
|
2022-10-28 11:37:29 +01:00
|
|
|
result = Inference{freshType(scope)};
|
2022-06-17 02:05:14 +01:00
|
|
|
}
|
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
LUAU_ASSERT(result.ty);
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
module->astTypes[expr] = result.ty;
|
2023-01-27 22:28:31 +00:00
|
|
|
if (expectedType)
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
module->astExpectedTypes[expr] = *expectedType;
|
2022-06-17 02:05:14 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-11-04 17:33:22 +00:00
|
|
|
Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprConstantString* string, std::optional<TypeId> expectedType, bool forceSingleton)
|
2022-10-28 11:37:29 +01:00
|
|
|
{
|
2022-11-04 17:33:22 +00:00
|
|
|
if (forceSingleton)
|
2023-01-04 20:53:17 +00:00
|
|
|
return Inference{arena->addType(SingletonType{StringSingleton{std::string{string->value.data, string->value.size}}})};
|
2022-11-04 17:33:22 +00:00
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
if (expectedType)
|
|
|
|
{
|
|
|
|
const TypeId expectedTy = follow(*expectedType);
|
2023-01-04 20:53:17 +00:00
|
|
|
if (get<BlockedType>(expectedTy) || get<PendingExpansionType>(expectedTy))
|
2022-10-28 11:37:29 +01:00
|
|
|
{
|
2023-01-04 20:53:17 +00:00
|
|
|
TypeId ty = arena->addType(BlockedType{});
|
|
|
|
TypeId singletonType = arena->addType(SingletonType(StringSingleton{std::string(string->value.data, string->value.size)}));
|
|
|
|
addConstraint(scope, string->location, PrimitiveTypeConstraint{ty, expectedTy, singletonType, builtinTypes->stringType});
|
2022-10-28 11:37:29 +01:00
|
|
|
return Inference{ty};
|
|
|
|
}
|
|
|
|
else if (maybeSingleton(expectedTy))
|
2023-01-04 20:53:17 +00:00
|
|
|
return Inference{arena->addType(SingletonType{StringSingleton{std::string{string->value.data, string->value.size}}})};
|
2022-10-28 11:37:29 +01:00
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
return Inference{builtinTypes->stringType};
|
2022-10-28 11:37:29 +01:00
|
|
|
}
|
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
return Inference{builtinTypes->stringType};
|
2022-10-28 11:37:29 +01:00
|
|
|
}
|
|
|
|
|
2022-11-04 17:33:22 +00:00
|
|
|
Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprConstantBool* boolExpr, std::optional<TypeId> expectedType, bool forceSingleton)
|
2022-10-28 11:37:29 +01:00
|
|
|
{
|
2023-01-04 20:53:17 +00:00
|
|
|
const TypeId singletonType = boolExpr->value ? builtinTypes->trueType : builtinTypes->falseType;
|
2022-11-04 17:33:22 +00:00
|
|
|
if (forceSingleton)
|
|
|
|
return Inference{singletonType};
|
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
if (expectedType)
|
|
|
|
{
|
|
|
|
const TypeId expectedTy = follow(*expectedType);
|
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
if (get<BlockedType>(expectedTy) || get<PendingExpansionType>(expectedTy))
|
2022-10-28 11:37:29 +01:00
|
|
|
{
|
2023-01-04 20:53:17 +00:00
|
|
|
TypeId ty = arena->addType(BlockedType{});
|
|
|
|
addConstraint(scope, boolExpr->location, PrimitiveTypeConstraint{ty, expectedTy, singletonType, builtinTypes->booleanType});
|
2022-10-28 11:37:29 +01:00
|
|
|
return Inference{ty};
|
|
|
|
}
|
|
|
|
else if (maybeSingleton(expectedTy))
|
|
|
|
return Inference{singletonType};
|
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
return Inference{builtinTypes->booleanType};
|
2022-10-28 11:37:29 +01:00
|
|
|
}
|
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
return Inference{builtinTypes->booleanType};
|
2022-10-28 11:37:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprLocal* local)
|
2022-10-21 18:54:01 +01:00
|
|
|
{
|
|
|
|
std::optional<TypeId> resultTy;
|
2022-11-04 17:33:22 +00:00
|
|
|
auto def = dfg->getDef(local);
|
|
|
|
if (def)
|
2022-10-21 18:54:01 +01:00
|
|
|
resultTy = scope->lookup(*def);
|
|
|
|
|
|
|
|
if (!resultTy)
|
|
|
|
{
|
|
|
|
if (auto ty = scope->lookup(local->local))
|
|
|
|
resultTy = *ty;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!resultTy)
|
2023-01-04 20:53:17 +00:00
|
|
|
return Inference{builtinTypes->errorRecoveryType()}; // TODO: replace with ice, locals should never exist before its definition.
|
2022-10-21 18:54:01 +01:00
|
|
|
|
2022-11-04 17:33:22 +00:00
|
|
|
if (def)
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
return Inference{*resultTy, refinementArena.proposition(*def, builtinTypes->truthyType)};
|
2022-11-04 17:33:22 +00:00
|
|
|
else
|
|
|
|
return Inference{*resultTy};
|
2022-10-21 18:54:01 +01:00
|
|
|
}
|
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprGlobal* global)
|
2022-10-21 18:54:01 +01:00
|
|
|
{
|
|
|
|
if (std::optional<TypeId> ty = scope->lookup(global->name))
|
2022-10-28 11:37:29 +01:00
|
|
|
return Inference{*ty};
|
2022-10-21 18:54:01 +01:00
|
|
|
|
|
|
|
/* prepopulateGlobalScope() has already added all global functions to the environment by this point, so any
|
|
|
|
* global that is not already in-scope is definitely an unknown symbol.
|
|
|
|
*/
|
|
|
|
reportError(global->location, UnknownSymbol{global->name.value});
|
2023-01-04 20:53:17 +00:00
|
|
|
return Inference{builtinTypes->errorRecoveryType()};
|
2022-10-21 18:54:01 +01:00
|
|
|
}
|
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprIndexName* indexName)
|
2022-06-17 02:05:14 +01:00
|
|
|
{
|
2022-10-28 11:37:29 +01:00
|
|
|
TypeId obj = check(scope, indexName->expr).ty;
|
2023-02-10 19:40:38 +00:00
|
|
|
TypeId result = freshType(scope);
|
2022-12-02 18:09:59 +00:00
|
|
|
|
|
|
|
std::optional<DefId> def = dfg->getDef(indexName);
|
|
|
|
if (def)
|
|
|
|
{
|
|
|
|
if (auto ty = scope->lookup(*def))
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
return Inference{*ty, refinementArena.proposition(*def, builtinTypes->truthyType)};
|
2022-12-02 18:09:59 +00:00
|
|
|
else
|
|
|
|
scope->dcrRefinements[*def] = result;
|
|
|
|
}
|
2022-06-17 02:05:14 +01:00
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
TableType::Props props{{indexName->index.value, Property{result}}};
|
2022-06-17 02:05:14 +01:00
|
|
|
const std::optional<TableIndexer> indexer;
|
2023-01-04 20:53:17 +00:00
|
|
|
TableType ttv{std::move(props), indexer, TypeLevel{}, scope.get(), TableState::Free};
|
2022-06-17 02:05:14 +01:00
|
|
|
|
|
|
|
TypeId expectedTableType = arena->addType(std::move(ttv));
|
2022-06-03 23:15:45 +01:00
|
|
|
|
2022-09-02 00:14:03 +01:00
|
|
|
addConstraint(scope, indexName->expr->location, SubtypeConstraint{obj, expectedTableType});
|
2022-06-17 02:05:14 +01:00
|
|
|
|
2022-12-02 18:09:59 +00:00
|
|
|
if (def)
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
return Inference{result, refinementArena.proposition(*def, builtinTypes->truthyType)};
|
2022-12-02 18:09:59 +00:00
|
|
|
else
|
|
|
|
return Inference{result};
|
2022-06-17 02:05:14 +01:00
|
|
|
}
|
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprIndexExpr* indexExpr)
|
2022-07-01 00:52:43 +01:00
|
|
|
{
|
2022-10-28 11:37:29 +01:00
|
|
|
TypeId obj = check(scope, indexExpr->expr).ty;
|
|
|
|
TypeId indexType = check(scope, indexExpr->index).ty;
|
2022-07-01 00:52:43 +01:00
|
|
|
|
|
|
|
TypeId result = freshType(scope);
|
|
|
|
|
|
|
|
TableIndexer indexer{indexType, result};
|
2023-01-04 20:53:17 +00:00
|
|
|
TypeId tableType = arena->addType(TableType{TableType::Props{}, TableIndexer{indexType, result}, TypeLevel{}, scope.get(), TableState::Free});
|
2022-07-01 00:52:43 +01:00
|
|
|
|
2022-09-02 00:14:03 +01:00
|
|
|
addConstraint(scope, indexExpr->expr->location, SubtypeConstraint{obj, tableType});
|
2022-07-01 00:52:43 +01:00
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
return Inference{result};
|
2022-07-01 00:52:43 +01:00
|
|
|
}
|
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprUnary* unary)
|
2022-07-01 00:52:43 +01:00
|
|
|
{
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
auto [operandType, refinement] = check(scope, unary->expr);
|
2023-01-04 20:53:17 +00:00
|
|
|
TypeId resultType = arena->addType(BlockedType{});
|
2022-09-23 20:17:25 +01:00
|
|
|
addConstraint(scope, unary->location, UnaryConstraint{unary->op, operandType, resultType});
|
2022-11-04 17:33:22 +00:00
|
|
|
|
|
|
|
if (unary->op == AstExprUnary::Not)
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
return Inference{resultType, refinementArena.negation(refinement)};
|
2022-11-04 17:33:22 +00:00
|
|
|
else
|
|
|
|
return Inference{resultType};
|
2022-10-21 18:54:01 +01:00
|
|
|
}
|
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprBinary* binary, std::optional<TypeId> expectedType)
|
2022-10-21 18:54:01 +01:00
|
|
|
{
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
auto [leftType, rightType, refinement] = checkBinary(scope, binary, expectedType);
|
2022-10-21 18:54:01 +01:00
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
TypeId resultType = arena->addType(BlockedType{});
|
|
|
|
addConstraint(scope, binary->location,
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
BinaryConstraint{binary->op, leftType, rightType, resultType, binary, &module->astOriginalCallTypes, &module->astOverloadResolvedTypes});
|
|
|
|
return Inference{resultType, std::move(refinement)};
|
2022-07-01 00:52:43 +01:00
|
|
|
}
|
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprIfElse* ifElse, std::optional<TypeId> expectedType)
|
2022-08-18 22:32:08 +01:00
|
|
|
{
|
2022-12-09 19:57:01 +00:00
|
|
|
ScopePtr condScope = childScope(ifElse->condition, scope);
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
auto [_, refinement] = check(scope, ifElse->condition);
|
2022-12-09 19:57:01 +00:00
|
|
|
|
|
|
|
ScopePtr thenScope = childScope(ifElse->trueExpr, scope);
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
applyRefinements(thenScope, ifElse->trueExpr->location, refinement);
|
2022-12-09 19:57:01 +00:00
|
|
|
TypeId thenType = check(thenScope, ifElse->trueExpr, expectedType).ty;
|
2022-08-18 22:32:08 +01:00
|
|
|
|
2022-12-09 19:57:01 +00:00
|
|
|
ScopePtr elseScope = childScope(ifElse->falseExpr, scope);
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
applyRefinements(elseScope, ifElse->falseExpr->location, refinementArena.negation(refinement));
|
2022-12-09 19:57:01 +00:00
|
|
|
TypeId elseType = check(elseScope, ifElse->falseExpr, expectedType).ty;
|
2022-08-18 22:32:08 +01:00
|
|
|
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
return Inference{expectedType ? *expectedType : arena->addType(UnionType{{thenType, elseType}})};
|
2022-08-18 22:32:08 +01:00
|
|
|
}
|
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprTypeAssertion* typeAssert)
|
2022-08-11 22:01:33 +01:00
|
|
|
{
|
2022-10-21 18:54:01 +01:00
|
|
|
check(scope, typeAssert->expr, std::nullopt);
|
2023-01-20 20:27:03 +00:00
|
|
|
return Inference{resolveType(scope, typeAssert->annotation, /* inTypeArguments */ false)};
|
2022-08-11 22:01:33 +01:00
|
|
|
}
|
|
|
|
|
2023-01-27 22:28:31 +00:00
|
|
|
Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprInterpString* interpString)
|
|
|
|
{
|
|
|
|
for (AstExpr* expr : interpString->expressions)
|
|
|
|
check(scope, expr);
|
|
|
|
|
|
|
|
return Inference{builtinTypes->stringType};
|
|
|
|
}
|
|
|
|
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
std::tuple<TypeId, TypeId, RefinementId> ConstraintGraphBuilder::checkBinary(
|
2022-11-04 17:33:22 +00:00
|
|
|
const ScopePtr& scope, AstExprBinary* binary, std::optional<TypeId> expectedType)
|
|
|
|
{
|
|
|
|
if (binary->op == AstExprBinary::And)
|
|
|
|
{
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
auto [leftType, leftRefinement] = check(scope, binary->left, expectedType);
|
2022-11-04 17:33:22 +00:00
|
|
|
|
|
|
|
ScopePtr rightScope = childScope(binary->right, scope);
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
applyRefinements(rightScope, binary->right->location, leftRefinement);
|
|
|
|
auto [rightType, rightRefinement] = check(rightScope, binary->right, expectedType);
|
2022-11-04 17:33:22 +00:00
|
|
|
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
return {leftType, rightType, refinementArena.conjunction(leftRefinement, rightRefinement)};
|
2022-11-04 17:33:22 +00:00
|
|
|
}
|
|
|
|
else if (binary->op == AstExprBinary::Or)
|
|
|
|
{
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
auto [leftType, leftRefinement] = check(scope, binary->left, expectedType);
|
2022-11-04 17:33:22 +00:00
|
|
|
|
|
|
|
ScopePtr rightScope = childScope(binary->right, scope);
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
applyRefinements(rightScope, binary->right->location, refinementArena.negation(leftRefinement));
|
|
|
|
auto [rightType, rightRefinement] = check(rightScope, binary->right, expectedType);
|
2022-11-04 17:33:22 +00:00
|
|
|
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
return {leftType, rightType, refinementArena.disjunction(leftRefinement, rightRefinement)};
|
2022-11-04 17:33:22 +00:00
|
|
|
}
|
2022-11-10 22:53:13 +00:00
|
|
|
else if (auto typeguard = matchTypeGuard(binary))
|
|
|
|
{
|
|
|
|
TypeId leftType = check(scope, binary->left).ty;
|
|
|
|
TypeId rightType = check(scope, binary->right).ty;
|
|
|
|
|
|
|
|
std::optional<DefId> def = dfg->getDef(typeguard->target);
|
|
|
|
if (!def)
|
|
|
|
return {leftType, rightType, nullptr};
|
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
TypeId discriminantTy = builtinTypes->neverType;
|
2022-11-10 22:53:13 +00:00
|
|
|
if (typeguard->type == "nil")
|
2023-01-04 20:53:17 +00:00
|
|
|
discriminantTy = builtinTypes->nilType;
|
2022-11-10 22:53:13 +00:00
|
|
|
else if (typeguard->type == "string")
|
2023-01-04 20:53:17 +00:00
|
|
|
discriminantTy = builtinTypes->stringType;
|
2022-11-10 22:53:13 +00:00
|
|
|
else if (typeguard->type == "number")
|
2023-01-04 20:53:17 +00:00
|
|
|
discriminantTy = builtinTypes->numberType;
|
2022-11-10 22:53:13 +00:00
|
|
|
else if (typeguard->type == "boolean")
|
2023-01-04 20:53:17 +00:00
|
|
|
discriminantTy = builtinTypes->threadType;
|
2022-11-10 22:53:13 +00:00
|
|
|
else if (typeguard->type == "table")
|
2023-01-27 22:28:31 +00:00
|
|
|
discriminantTy = builtinTypes->tableType;
|
2022-11-10 22:53:13 +00:00
|
|
|
else if (typeguard->type == "function")
|
2023-01-04 20:53:17 +00:00
|
|
|
discriminantTy = builtinTypes->functionType;
|
2022-11-10 22:53:13 +00:00
|
|
|
else if (typeguard->type == "userdata")
|
|
|
|
{
|
|
|
|
// For now, we don't really care about being accurate with userdata if the typeguard was using typeof
|
2023-01-04 20:53:17 +00:00
|
|
|
discriminantTy = builtinTypes->neverType; // TODO: replace with top class type
|
2022-11-10 22:53:13 +00:00
|
|
|
}
|
|
|
|
else if (!typeguard->isTypeof && typeguard->type == "vector")
|
2023-01-04 20:53:17 +00:00
|
|
|
discriminantTy = builtinTypes->neverType; // TODO: figure out a way to deal with this quirky type
|
2022-11-10 22:53:13 +00:00
|
|
|
else if (!typeguard->isTypeof)
|
2023-01-04 20:53:17 +00:00
|
|
|
discriminantTy = builtinTypes->neverType;
|
2022-11-10 22:53:13 +00:00
|
|
|
else if (auto typeFun = globalScope->lookupType(typeguard->type); typeFun && typeFun->typeParams.empty() && typeFun->typePackParams.empty())
|
|
|
|
{
|
|
|
|
TypeId ty = follow(typeFun->type);
|
|
|
|
|
|
|
|
// We're only interested in the root class of any classes.
|
2023-01-20 20:27:03 +00:00
|
|
|
if (auto ctv = get<ClassType>(ty); !ctv || (FFlag::LuauNegatedClassTypes ? (ctv->parent == builtinTypes->classType) : !ctv->parent))
|
2022-11-10 22:53:13 +00:00
|
|
|
discriminantTy = ty;
|
|
|
|
}
|
|
|
|
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
RefinementId proposition = refinementArena.proposition(*def, discriminantTy);
|
2022-11-10 22:53:13 +00:00
|
|
|
if (binary->op == AstExprBinary::CompareEq)
|
|
|
|
return {leftType, rightType, proposition};
|
|
|
|
else if (binary->op == AstExprBinary::CompareNe)
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
return {leftType, rightType, refinementArena.negation(proposition)};
|
2022-11-10 22:53:13 +00:00
|
|
|
else
|
|
|
|
ice->ice("matchTypeGuard should only return a Some under `==` or `~=`!");
|
|
|
|
}
|
2022-11-04 17:33:22 +00:00
|
|
|
else if (binary->op == AstExprBinary::CompareEq || binary->op == AstExprBinary::CompareNe)
|
|
|
|
{
|
|
|
|
TypeId leftType = check(scope, binary->left, expectedType, true).ty;
|
|
|
|
TypeId rightType = check(scope, binary->right, expectedType, true).ty;
|
|
|
|
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
RefinementId leftRefinement = nullptr;
|
2022-11-04 17:33:22 +00:00
|
|
|
if (auto def = dfg->getDef(binary->left))
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
leftRefinement = refinementArena.proposition(*def, rightType);
|
2022-11-04 17:33:22 +00:00
|
|
|
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
RefinementId rightRefinement = nullptr;
|
2022-11-04 17:33:22 +00:00
|
|
|
if (auto def = dfg->getDef(binary->right))
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
rightRefinement = refinementArena.proposition(*def, leftType);
|
2022-11-04 17:33:22 +00:00
|
|
|
|
|
|
|
if (binary->op == AstExprBinary::CompareNe)
|
|
|
|
{
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
leftRefinement = refinementArena.negation(leftRefinement);
|
|
|
|
rightRefinement = refinementArena.negation(rightRefinement);
|
2022-11-04 17:33:22 +00:00
|
|
|
}
|
|
|
|
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
return {leftType, rightType, refinementArena.equivalence(leftRefinement, rightRefinement)};
|
2022-11-04 17:33:22 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TypeId leftType = check(scope, binary->left, expectedType).ty;
|
|
|
|
TypeId rightType = check(scope, binary->right, expectedType).ty;
|
|
|
|
return {leftType, rightType, nullptr};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-21 18:54:01 +01:00
|
|
|
TypePackId ConstraintGraphBuilder::checkLValues(const ScopePtr& scope, AstArray<AstExpr*> exprs)
|
|
|
|
{
|
|
|
|
std::vector<TypeId> types;
|
|
|
|
types.reserve(exprs.size);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < exprs.size; ++i)
|
|
|
|
{
|
|
|
|
AstExpr* const expr = exprs.data[i];
|
|
|
|
types.push_back(checkLValue(scope, expr));
|
|
|
|
}
|
|
|
|
|
|
|
|
return arena->addTypePack(std::move(types));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function is mostly about identifying properties that are being inserted into unsealed tables.
|
|
|
|
*
|
|
|
|
* If expr has the form name.a.b.c
|
|
|
|
*/
|
|
|
|
TypeId ConstraintGraphBuilder::checkLValue(const ScopePtr& scope, AstExpr* expr)
|
|
|
|
{
|
|
|
|
if (auto indexExpr = expr->as<AstExprIndexExpr>())
|
|
|
|
{
|
|
|
|
if (auto constantString = indexExpr->index->as<AstExprConstantString>())
|
|
|
|
{
|
|
|
|
AstName syntheticIndex{constantString->value.data};
|
|
|
|
AstExprIndexName synthetic{
|
|
|
|
indexExpr->location, indexExpr->expr, syntheticIndex, constantString->location, indexExpr->expr->location.end, '.'};
|
|
|
|
return checkLValue(scope, &synthetic);
|
|
|
|
}
|
|
|
|
}
|
2022-11-18 19:47:21 +00:00
|
|
|
else if (!expr->is<AstExprIndexName>())
|
|
|
|
return check(scope, expr).ty;
|
2022-10-21 18:54:01 +01:00
|
|
|
|
2023-01-20 20:27:03 +00:00
|
|
|
Symbol sym;
|
|
|
|
std::vector<std::string> segments;
|
|
|
|
std::vector<AstExpr*> exprs;
|
|
|
|
|
|
|
|
AstExpr* e = expr;
|
|
|
|
while (e)
|
|
|
|
{
|
|
|
|
if (auto global = e->as<AstExprGlobal>())
|
|
|
|
{
|
|
|
|
sym = global->name;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (auto local = e->as<AstExprLocal>())
|
|
|
|
{
|
|
|
|
sym = local->local;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (auto indexName = e->as<AstExprIndexName>())
|
|
|
|
{
|
|
|
|
segments.push_back(indexName->index.value);
|
|
|
|
exprs.push_back(e);
|
|
|
|
e = indexName->expr;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return check(scope, expr).ty;
|
|
|
|
}
|
2022-10-21 18:54:01 +01:00
|
|
|
|
2022-11-18 19:47:21 +00:00
|
|
|
LUAU_ASSERT(!segments.empty());
|
2022-10-21 18:54:01 +01:00
|
|
|
|
2023-01-20 20:27:03 +00:00
|
|
|
std::reverse(begin(segments), end(segments));
|
|
|
|
std::reverse(begin(exprs), end(exprs));
|
|
|
|
|
2022-10-21 18:54:01 +01:00
|
|
|
auto lookupResult = scope->lookupEx(sym);
|
|
|
|
if (!lookupResult)
|
2022-10-28 11:37:29 +01:00
|
|
|
return check(scope, expr).ty;
|
2022-11-18 19:47:21 +00:00
|
|
|
const auto [subjectType, symbolScope] = std::move(*lookupResult);
|
2022-10-21 18:54:01 +01:00
|
|
|
|
2022-11-18 19:47:21 +00:00
|
|
|
TypeId propTy = freshType(scope);
|
2022-10-21 18:54:01 +01:00
|
|
|
|
2022-11-18 19:47:21 +00:00
|
|
|
std::vector<std::string> segmentStrings(begin(segments), end(segments));
|
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
TypeId updatedType = arena->addType(BlockedType{});
|
2022-11-18 19:47:21 +00:00
|
|
|
addConstraint(scope, expr->location, SetPropConstraint{updatedType, subjectType, std::move(segmentStrings), propTy});
|
2022-10-21 18:54:01 +01:00
|
|
|
|
2023-01-20 20:27:03 +00:00
|
|
|
TypeId prevSegmentTy = updatedType;
|
|
|
|
for (size_t i = 0; i < segments.size(); ++i)
|
|
|
|
{
|
|
|
|
TypeId segmentTy = arena->addType(BlockedType{});
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
module->astTypes[exprs[i]] = segmentTy;
|
2023-01-20 20:27:03 +00:00
|
|
|
addConstraint(scope, expr->location, HasPropConstraint{segmentTy, prevSegmentTy, segments[i]});
|
|
|
|
prevSegmentTy = segmentTy;
|
|
|
|
}
|
|
|
|
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
module->astTypes[expr] = prevSegmentTy;
|
|
|
|
module->astTypes[e] = updatedType;
|
2023-02-10 19:40:38 +00:00
|
|
|
|
|
|
|
symbolScope->bindings[sym].typeId = updatedType;
|
|
|
|
|
|
|
|
std::optional<DefId> def = dfg->getDef(sym);
|
|
|
|
if (def)
|
|
|
|
{
|
|
|
|
// This can fail if the user is erroneously trying to augment a builtin
|
|
|
|
// table like os or string.
|
|
|
|
symbolScope->dcrRefinements[*def] = updatedType;
|
|
|
|
}
|
2022-11-18 19:47:21 +00:00
|
|
|
|
|
|
|
return propTy;
|
2022-10-21 18:54:01 +01:00
|
|
|
}
|
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprTable* expr, std::optional<TypeId> expectedType)
|
2022-06-17 02:05:14 +01:00
|
|
|
{
|
2023-01-04 20:53:17 +00:00
|
|
|
TypeId ty = arena->addType(TableType{});
|
|
|
|
TableType* ttv = getMutable<TableType>(ty);
|
2022-06-17 02:05:14 +01:00
|
|
|
LUAU_ASSERT(ttv);
|
|
|
|
|
2022-09-29 23:23:10 +01:00
|
|
|
ttv->state = TableState::Unsealed;
|
|
|
|
ttv->scope = scope.get();
|
|
|
|
|
2022-09-02 00:14:03 +01:00
|
|
|
auto createIndexer = [this, scope, ttv](const Location& location, TypeId currentIndexType, TypeId currentResultType) {
|
2022-06-17 02:05:14 +01:00
|
|
|
if (!ttv->indexer)
|
2022-06-03 23:15:45 +01:00
|
|
|
{
|
2022-06-17 02:05:14 +01:00
|
|
|
TypeId indexType = this->freshType(scope);
|
|
|
|
TypeId resultType = this->freshType(scope);
|
|
|
|
ttv->indexer = TableIndexer{indexType, resultType};
|
2022-06-03 23:15:45 +01:00
|
|
|
}
|
|
|
|
|
2022-09-02 00:14:03 +01:00
|
|
|
addConstraint(scope, location, SubtypeConstraint{ttv->indexer->indexType, currentIndexType});
|
|
|
|
addConstraint(scope, location, SubtypeConstraint{ttv->indexer->indexResultType, currentResultType});
|
2022-06-17 02:05:14 +01:00
|
|
|
};
|
2022-06-03 23:15:45 +01:00
|
|
|
|
2023-02-10 19:40:38 +00:00
|
|
|
std::optional<TypeId> annotatedKeyType;
|
|
|
|
std::optional<TypeId> annotatedIndexResultType;
|
|
|
|
|
|
|
|
if (expectedType)
|
|
|
|
{
|
|
|
|
if (const TableType* ttv = get<TableType>(follow(*expectedType)))
|
|
|
|
{
|
|
|
|
if (ttv->indexer)
|
|
|
|
{
|
|
|
|
annotatedKeyType.emplace(follow(ttv->indexer->indexType));
|
|
|
|
annotatedIndexResultType.emplace(ttv->indexer->indexResultType);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isIndexedResultType = false;
|
|
|
|
std::optional<TypeId> pinnedIndexResultType;
|
|
|
|
|
|
|
|
|
2022-06-17 02:05:14 +01:00
|
|
|
for (const AstExprTable::Item& item : expr->items)
|
|
|
|
{
|
2022-09-23 20:17:25 +01:00
|
|
|
std::optional<TypeId> expectedValueType;
|
2023-02-10 19:40:38 +00:00
|
|
|
if (item.kind == AstExprTable::Item::Kind::General || item.kind == AstExprTable::Item::Kind::List)
|
|
|
|
isIndexedResultType = true;
|
2022-09-23 20:17:25 +01:00
|
|
|
|
|
|
|
if (item.key && expectedType)
|
|
|
|
{
|
|
|
|
if (auto stringKey = item.key->as<AstExprConstantString>())
|
|
|
|
{
|
2022-12-02 18:09:59 +00:00
|
|
|
ErrorVec errorVec;
|
|
|
|
std::optional<TypeId> propTy =
|
2023-01-04 20:53:17 +00:00
|
|
|
findTablePropertyRespectingMeta(builtinTypes, errorVec, follow(*expectedType), stringKey->value.data, item.value->location);
|
2022-12-02 18:09:59 +00:00
|
|
|
if (propTy)
|
|
|
|
expectedValueType = propTy;
|
|
|
|
else
|
|
|
|
{
|
2023-01-04 20:53:17 +00:00
|
|
|
expectedValueType = arena->addType(BlockedType{});
|
2022-12-02 18:09:59 +00:00
|
|
|
addConstraint(scope, item.value->location, HasPropConstraint{*expectedValueType, *expectedType, stringKey->value.data});
|
|
|
|
}
|
2022-09-23 20:17:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-10 19:40:38 +00:00
|
|
|
|
|
|
|
// We'll resolve the expected index result type here with the following priority:
|
|
|
|
// 1. Record table types - in which key, value pairs must be handled on a k,v pair basis.
|
|
|
|
// In this case, the above if-statement will populate expectedValueType
|
|
|
|
// 2. Someone places an annotation on a General or List table
|
|
|
|
// Trust the annotation and have the solver inform them if they get it wrong
|
|
|
|
// 3. Someone omits the annotation on a general or List table
|
|
|
|
// Use the type of the first indexResultType as the expected type
|
|
|
|
std::optional<TypeId> checkExpectedIndexResultType;
|
|
|
|
if (expectedValueType)
|
|
|
|
{
|
|
|
|
checkExpectedIndexResultType = expectedValueType;
|
|
|
|
}
|
|
|
|
else if (annotatedIndexResultType)
|
|
|
|
{
|
|
|
|
checkExpectedIndexResultType = annotatedIndexResultType;
|
|
|
|
}
|
|
|
|
else if (pinnedIndexResultType)
|
|
|
|
{
|
|
|
|
checkExpectedIndexResultType = pinnedIndexResultType;
|
|
|
|
}
|
|
|
|
|
|
|
|
TypeId itemTy = check(scope, item.value, checkExpectedIndexResultType).ty;
|
|
|
|
|
|
|
|
if (isIndexedResultType && !pinnedIndexResultType)
|
|
|
|
pinnedIndexResultType = itemTy;
|
2022-06-03 23:15:45 +01:00
|
|
|
|
2022-06-17 02:05:14 +01:00
|
|
|
if (item.key)
|
|
|
|
{
|
|
|
|
// Even though we don't need to use the type of the item's key if
|
|
|
|
// it's a string constant, we still want to check it to populate
|
|
|
|
// astTypes.
|
2023-02-10 19:40:38 +00:00
|
|
|
TypeId keyTy = check(scope, item.key, annotatedKeyType).ty;
|
2022-06-17 02:05:14 +01:00
|
|
|
|
|
|
|
if (AstExprConstantString* key = item.key->as<AstExprConstantString>())
|
|
|
|
{
|
|
|
|
ttv->props[key->value.begin()] = {itemTy};
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-09-02 00:14:03 +01:00
|
|
|
createIndexer(item.key->location, keyTy, itemTy);
|
2022-06-17 02:05:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-01-04 20:53:17 +00:00
|
|
|
TypeId numberType = builtinTypes->numberType;
|
2022-09-02 00:14:03 +01:00
|
|
|
// FIXME? The location isn't quite right here. Not sure what is
|
|
|
|
// right.
|
|
|
|
createIndexer(item.value->location, numberType, itemTy);
|
2022-06-17 02:05:14 +01:00
|
|
|
}
|
2022-06-03 23:15:45 +01:00
|
|
|
}
|
2022-06-17 02:05:14 +01:00
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
return Inference{ty};
|
2022-06-17 02:05:14 +01:00
|
|
|
}
|
|
|
|
|
2022-12-02 18:09:59 +00:00
|
|
|
ConstraintGraphBuilder::FunctionSignature ConstraintGraphBuilder::checkFunctionSignature(
|
|
|
|
const ScopePtr& parent, AstExprFunction* fn, std::optional<TypeId> expectedType)
|
2022-06-17 02:05:14 +01:00
|
|
|
{
|
2022-07-29 05:24:07 +01:00
|
|
|
ScopePtr signatureScope = nullptr;
|
|
|
|
ScopePtr bodyScope = nullptr;
|
2022-07-01 00:52:43 +01:00
|
|
|
TypePackId returnType = nullptr;
|
|
|
|
|
|
|
|
std::vector<TypeId> genericTypes;
|
|
|
|
std::vector<TypePackId> genericTypePacks;
|
|
|
|
|
2022-12-02 18:09:59 +00:00
|
|
|
if (expectedType)
|
|
|
|
expectedType = follow(*expectedType);
|
|
|
|
|
2022-07-01 00:52:43 +01:00
|
|
|
bool hasGenerics = fn->generics.size > 0 || fn->genericPacks.size > 0;
|
|
|
|
|
2022-12-02 18:09:59 +00:00
|
|
|
signatureScope = childScope(fn, parent);
|
2022-07-01 00:52:43 +01:00
|
|
|
|
2022-12-02 18:09:59 +00:00
|
|
|
// We need to assign returnType before creating bodyScope so that the
|
|
|
|
// return type gets propogated to bodyScope.
|
|
|
|
returnType = freshTypePack(signatureScope);
|
|
|
|
signatureScope->returnType = returnType;
|
2022-07-01 00:52:43 +01:00
|
|
|
|
2022-12-02 18:09:59 +00:00
|
|
|
bodyScope = childScope(fn->body, signatureScope);
|
2022-07-01 00:52:43 +01:00
|
|
|
|
2022-12-02 18:09:59 +00:00
|
|
|
if (hasGenerics)
|
|
|
|
{
|
2022-07-29 05:24:07 +01:00
|
|
|
std::vector<std::pair<Name, GenericTypeDefinition>> genericDefinitions = createGenerics(signatureScope, fn->generics);
|
|
|
|
std::vector<std::pair<Name, GenericTypePackDefinition>> genericPackDefinitions = createGenericPacks(signatureScope, fn->genericPacks);
|
2022-07-01 00:52:43 +01:00
|
|
|
|
|
|
|
// We do not support default values on function generics, so we only
|
|
|
|
// care about the types involved.
|
|
|
|
for (const auto& [name, g] : genericDefinitions)
|
|
|
|
{
|
|
|
|
genericTypes.push_back(g.ty);
|
2022-08-11 22:01:33 +01:00
|
|
|
signatureScope->privateTypeBindings[name] = TypeFun{g.ty};
|
2022-07-01 00:52:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto& [name, g] : genericPackDefinitions)
|
|
|
|
{
|
|
|
|
genericTypePacks.push_back(g.tp);
|
2022-08-11 22:01:33 +01:00
|
|
|
signatureScope->privateTypePackBindings[name] = g.tp;
|
2022-07-01 00:52:43 +01:00
|
|
|
}
|
2022-12-02 18:09:59 +00:00
|
|
|
|
|
|
|
// Local variable works around an odd gcc 11.3 warning: <anonymous> may be used uninitialized
|
|
|
|
std::optional<TypeId> none = std::nullopt;
|
|
|
|
expectedType = none;
|
2022-07-01 00:52:43 +01:00
|
|
|
}
|
2022-12-02 18:09:59 +00:00
|
|
|
|
|
|
|
std::vector<TypeId> argTypes;
|
2023-02-17 23:41:51 +00:00
|
|
|
std::vector<std::optional<FunctionArgument>> argNames;
|
2022-12-02 18:09:59 +00:00
|
|
|
TypePack expectedArgPack;
|
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
const FunctionType* expectedFunction = expectedType ? get<FunctionType>(*expectedType) : nullptr;
|
2022-12-02 18:09:59 +00:00
|
|
|
|
|
|
|
if (expectedFunction)
|
2022-07-01 00:52:43 +01:00
|
|
|
{
|
2023-01-04 20:53:17 +00:00
|
|
|
expectedArgPack = extendTypePack(*arena, builtinTypes, expectedFunction->argTypes, fn->args.size);
|
2022-12-02 18:09:59 +00:00
|
|
|
|
|
|
|
genericTypes = expectedFunction->generics;
|
|
|
|
genericTypePacks = expectedFunction->genericPacks;
|
|
|
|
}
|
2022-07-01 00:52:43 +01:00
|
|
|
|
2023-02-17 23:41:51 +00:00
|
|
|
if (fn->self)
|
|
|
|
{
|
|
|
|
TypeId selfType = freshType(signatureScope);
|
|
|
|
argTypes.push_back(selfType);
|
|
|
|
argNames.emplace_back(FunctionArgument{fn->self->name.value, fn->self->location});
|
|
|
|
signatureScope->bindings[fn->self] = Binding{selfType, fn->self->location};
|
|
|
|
}
|
|
|
|
|
2022-12-02 18:09:59 +00:00
|
|
|
for (size_t i = 0; i < fn->args.size; ++i)
|
|
|
|
{
|
|
|
|
AstLocal* local = fn->args.data[i];
|
|
|
|
|
|
|
|
TypeId t = freshType(signatureScope);
|
|
|
|
argTypes.push_back(t);
|
2023-02-17 23:41:51 +00:00
|
|
|
argNames.emplace_back(FunctionArgument{local->name.value, local->location});
|
2022-12-02 18:09:59 +00:00
|
|
|
signatureScope->bindings[local] = Binding{t, local->location};
|
|
|
|
|
2023-02-17 23:41:51 +00:00
|
|
|
auto def = dfg->getDef(local);
|
|
|
|
LUAU_ASSERT(def);
|
|
|
|
signatureScope->dcrRefinements[*def] = t;
|
|
|
|
|
2022-12-02 18:09:59 +00:00
|
|
|
TypeId annotationTy = t;
|
|
|
|
|
|
|
|
if (local->annotation)
|
|
|
|
{
|
2023-01-20 20:27:03 +00:00
|
|
|
annotationTy = resolveType(signatureScope, local->annotation, /* inTypeArguments */ false);
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
// If we provide an annotation that is wrong, type inference should ignore the annotation
|
|
|
|
// and try to infer a fresh type, like in the old solver
|
|
|
|
if (get<ErrorType>(follow(annotationTy)))
|
|
|
|
annotationTy = freshType(signatureScope);
|
2022-12-02 18:09:59 +00:00
|
|
|
addConstraint(signatureScope, local->annotation->location, SubtypeConstraint{t, annotationTy});
|
|
|
|
}
|
|
|
|
else if (i < expectedArgPack.head.size())
|
|
|
|
{
|
|
|
|
addConstraint(signatureScope, local->location, SubtypeConstraint{t, expectedArgPack.head[i]});
|
|
|
|
}
|
2022-07-01 00:52:43 +01:00
|
|
|
}
|
|
|
|
|
2022-09-15 23:38:17 +01:00
|
|
|
TypePackId varargPack = nullptr;
|
2022-09-08 23:14:25 +01:00
|
|
|
|
|
|
|
if (fn->vararg)
|
|
|
|
{
|
|
|
|
if (fn->varargAnnotation)
|
|
|
|
{
|
2023-01-20 20:27:03 +00:00
|
|
|
TypePackId annotationType = resolveTypePack(signatureScope, fn->varargAnnotation, /* inTypeArguments */ false);
|
2022-09-08 23:14:25 +01:00
|
|
|
varargPack = annotationType;
|
|
|
|
}
|
2022-12-02 18:09:59 +00:00
|
|
|
else if (expectedArgPack.tail && get<VariadicTypePack>(*expectedArgPack.tail))
|
|
|
|
varargPack = *expectedArgPack.tail;
|
2022-09-08 23:14:25 +01:00
|
|
|
else
|
2023-01-04 20:53:17 +00:00
|
|
|
varargPack = builtinTypes->anyTypePack;
|
2022-09-08 23:14:25 +01:00
|
|
|
|
|
|
|
signatureScope->varargPack = varargPack;
|
2022-12-02 18:09:59 +00:00
|
|
|
bodyScope->varargPack = varargPack;
|
2022-09-08 23:14:25 +01:00
|
|
|
}
|
2022-09-15 23:38:17 +01:00
|
|
|
else
|
|
|
|
{
|
2023-01-04 20:53:17 +00:00
|
|
|
varargPack = arena->addTypePack(VariadicTypePack{builtinTypes->anyType, /*hidden*/ true});
|
2022-09-15 23:38:17 +01:00
|
|
|
// We do not add to signatureScope->varargPack because ... is not valid
|
|
|
|
// in functions without an explicit ellipsis.
|
2022-12-02 18:09:59 +00:00
|
|
|
|
|
|
|
signatureScope->varargPack = std::nullopt;
|
|
|
|
bodyScope->varargPack = std::nullopt;
|
2022-09-15 23:38:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
LUAU_ASSERT(nullptr != varargPack);
|
2022-09-08 23:14:25 +01:00
|
|
|
|
2022-12-02 18:09:59 +00:00
|
|
|
// If there is both an annotation and an expected type, the annotation wins.
|
|
|
|
// Type checking will sort out any discrepancies later.
|
2022-06-24 02:56:00 +01:00
|
|
|
if (fn->returnAnnotation)
|
|
|
|
{
|
2023-01-20 20:27:03 +00:00
|
|
|
TypePackId annotatedRetType = resolveTypePack(signatureScope, *fn->returnAnnotation, /* inTypeArguments */ false);
|
2022-09-23 20:17:25 +01:00
|
|
|
|
|
|
|
// We bind the annotated type directly here so that, when we need to
|
|
|
|
// generate constraints for return types, we have a guarantee that we
|
|
|
|
// know the annotated return type already, if one was provided.
|
|
|
|
LUAU_ASSERT(get<FreeTypePack>(returnType));
|
|
|
|
asMutable(returnType)->ty.emplace<BoundTypePack>(annotatedRetType);
|
2022-06-24 02:56:00 +01:00
|
|
|
}
|
2022-12-02 18:09:59 +00:00
|
|
|
else if (expectedFunction)
|
2022-06-03 23:15:45 +01:00
|
|
|
{
|
2022-12-02 18:09:59 +00:00
|
|
|
asMutable(returnType)->ty.emplace<BoundTypePack>(expectedFunction->retTypes);
|
2022-06-17 02:05:14 +01:00
|
|
|
}
|
|
|
|
|
2022-07-01 00:52:43 +01:00
|
|
|
// TODO: Preserve argument names in the function's type.
|
2022-06-24 02:56:00 +01:00
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
FunctionType actualFunction{TypeLevel{}, parent.get(), arena->addTypePack(argTypes, varargPack), returnType};
|
2022-07-01 00:52:43 +01:00
|
|
|
actualFunction.hasNoGenerics = !hasGenerics;
|
|
|
|
actualFunction.generics = std::move(genericTypes);
|
|
|
|
actualFunction.genericPacks = std::move(genericTypePacks);
|
2023-02-17 23:41:51 +00:00
|
|
|
actualFunction.argNames = std::move(argNames);
|
2022-07-01 00:52:43 +01:00
|
|
|
|
2022-06-17 02:05:14 +01:00
|
|
|
TypeId actualFunctionType = arena->addType(std::move(actualFunction));
|
|
|
|
LUAU_ASSERT(actualFunctionType);
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
module->astTypes[fn] = actualFunctionType;
|
2022-06-17 02:05:14 +01:00
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
if (expectedType && get<FreeType>(*expectedType))
|
2022-12-02 18:09:59 +00:00
|
|
|
{
|
2023-01-04 20:53:17 +00:00
|
|
|
asMutable(*expectedType)->ty.emplace<BoundType>(actualFunctionType);
|
2022-12-02 18:09:59 +00:00
|
|
|
}
|
|
|
|
|
2022-07-01 00:52:43 +01:00
|
|
|
return {
|
|
|
|
/* signature */ actualFunctionType,
|
2022-12-02 18:09:59 +00:00
|
|
|
/* signatureScope */ signatureScope,
|
2022-07-29 05:24:07 +01:00
|
|
|
/* bodyScope */ bodyScope,
|
2022-07-01 00:52:43 +01:00
|
|
|
};
|
2022-06-17 02:05:14 +01:00
|
|
|
}
|
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
void ConstraintGraphBuilder::checkFunctionBody(const ScopePtr& scope, AstExprFunction* fn)
|
2022-06-17 02:05:14 +01:00
|
|
|
{
|
2022-07-01 00:52:43 +01:00
|
|
|
visitBlockWithoutChildScope(scope, fn->body);
|
2022-06-17 02:05:14 +01:00
|
|
|
|
|
|
|
// If it is possible for execution to reach the end of the function, the return type must be compatible with ()
|
|
|
|
|
|
|
|
if (nullptr != getFallthrough(fn->body))
|
|
|
|
{
|
|
|
|
TypePackId empty = arena->addTypePack({}); // TODO we could have CSG retain one of these forever
|
2022-09-02 00:14:03 +01:00
|
|
|
addConstraint(scope, fn->location, PackSubtypeConstraint{scope->returnType, empty});
|
2022-06-24 02:56:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-20 20:27:03 +00:00
|
|
|
TypeId ConstraintGraphBuilder::resolveType(const ScopePtr& scope, AstType* ty, bool inTypeArguments)
|
2022-06-24 02:56:00 +01:00
|
|
|
{
|
|
|
|
TypeId result = nullptr;
|
|
|
|
|
|
|
|
if (auto ref = ty->as<AstTypeReference>())
|
|
|
|
{
|
2022-09-29 23:23:10 +01:00
|
|
|
if (FFlag::DebugLuauMagicTypes)
|
|
|
|
{
|
|
|
|
if (ref->name == "_luau_ice")
|
|
|
|
ice->ice("_luau_ice encountered", ty->location);
|
|
|
|
else if (ref->name == "_luau_print")
|
|
|
|
{
|
|
|
|
if (ref->parameters.size != 1 || !ref->parameters.data[0].type)
|
|
|
|
{
|
|
|
|
reportError(ty->location, GenericError{"_luau_print requires one generic parameter"});
|
2023-01-04 20:53:17 +00:00
|
|
|
return builtinTypes->errorRecoveryType();
|
2022-09-29 23:23:10 +01:00
|
|
|
}
|
|
|
|
else
|
2023-01-20 20:27:03 +00:00
|
|
|
return resolveType(scope, ref->parameters.data[0].type, inTypeArguments);
|
2022-09-29 23:23:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
std::optional<TypeFun> alias;
|
2022-08-04 23:35:33 +01:00
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
if (ref->prefix.has_value())
|
|
|
|
{
|
|
|
|
alias = scope->lookupImportedType(ref->prefix->value, ref->name.value);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
alias = scope->lookupType(ref->name.value);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (alias.has_value())
|
2022-08-04 23:35:33 +01:00
|
|
|
{
|
|
|
|
// If the alias is not generic, we don't need to set up a blocked
|
|
|
|
// type and an instantiation constraint.
|
2022-09-02 00:14:03 +01:00
|
|
|
if (alias.has_value() && alias->typeParams.empty() && alias->typePackParams.empty())
|
2022-08-04 23:35:33 +01:00
|
|
|
{
|
|
|
|
result = alias->type;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::vector<TypeId> parameters;
|
|
|
|
std::vector<TypePackId> packParameters;
|
|
|
|
|
|
|
|
for (const AstTypeOrPack& p : ref->parameters)
|
|
|
|
{
|
|
|
|
// We do not enforce the ordering of types vs. type packs here;
|
|
|
|
// that is done in the parser.
|
|
|
|
if (p.type)
|
|
|
|
{
|
2023-01-20 20:27:03 +00:00
|
|
|
parameters.push_back(resolveType(scope, p.type, /* inTypeArguments */ true));
|
2022-08-04 23:35:33 +01:00
|
|
|
}
|
|
|
|
else if (p.typePack)
|
|
|
|
{
|
2023-01-20 20:27:03 +00:00
|
|
|
packParameters.push_back(resolveTypePack(scope, p.typePack, /* inTypeArguments */ true));
|
2022-08-04 23:35:33 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// This indicates a parser bug: one of these two pointers
|
|
|
|
// should be set.
|
|
|
|
LUAU_ASSERT(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
result = arena->addType(PendingExpansionType{ref->prefix, ref->name, parameters, packParameters});
|
2022-08-04 23:35:33 +01:00
|
|
|
|
2023-01-20 20:27:03 +00:00
|
|
|
// If we're not in a type argument context, we need to create a constraint that expands this.
|
|
|
|
// The dispatching of the above constraint will queue up additional constraints for nested
|
|
|
|
// type function applications.
|
|
|
|
if (!inTypeArguments)
|
2022-09-02 00:14:03 +01:00
|
|
|
addConstraint(scope, ty->location, TypeAliasExpansionConstraint{/* target */ result});
|
2022-08-04 23:35:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-01-04 20:53:17 +00:00
|
|
|
result = builtinTypes->errorRecoveryType();
|
2022-08-04 23:35:33 +01:00
|
|
|
}
|
2022-06-03 23:15:45 +01:00
|
|
|
}
|
2022-06-24 02:56:00 +01:00
|
|
|
else if (auto tab = ty->as<AstTypeTable>())
|
|
|
|
{
|
2023-01-04 20:53:17 +00:00
|
|
|
TableType::Props props;
|
2022-06-24 02:56:00 +01:00
|
|
|
std::optional<TableIndexer> indexer;
|
|
|
|
|
|
|
|
for (const AstTableProp& prop : tab->props)
|
|
|
|
{
|
|
|
|
std::string name = prop.name.value;
|
|
|
|
// TODO: Recursion limit.
|
2023-01-20 20:27:03 +00:00
|
|
|
TypeId propTy = resolveType(scope, prop.type, inTypeArguments);
|
2022-06-24 02:56:00 +01:00
|
|
|
// TODO: Fill in location.
|
|
|
|
props[name] = {propTy};
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tab->indexer)
|
|
|
|
{
|
|
|
|
// TODO: Recursion limit.
|
|
|
|
indexer = TableIndexer{
|
2023-01-20 20:27:03 +00:00
|
|
|
resolveType(scope, tab->indexer->indexType, inTypeArguments),
|
|
|
|
resolveType(scope, tab->indexer->resultType, inTypeArguments),
|
2022-06-24 02:56:00 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
result = arena->addType(TableType{props, indexer, scope->level, scope.get(), TableState::Sealed});
|
2022-06-24 02:56:00 +01:00
|
|
|
}
|
|
|
|
else if (auto fn = ty->as<AstTypeFunction>())
|
|
|
|
{
|
|
|
|
// TODO: Recursion limit.
|
2022-07-01 00:52:43 +01:00
|
|
|
bool hasGenerics = fn->generics.size > 0 || fn->genericPacks.size > 0;
|
2022-07-29 05:24:07 +01:00
|
|
|
ScopePtr signatureScope = nullptr;
|
2022-07-01 00:52:43 +01:00
|
|
|
|
|
|
|
std::vector<TypeId> genericTypes;
|
|
|
|
std::vector<TypePackId> genericTypePacks;
|
2022-06-24 02:56:00 +01:00
|
|
|
|
2022-07-01 00:52:43 +01:00
|
|
|
// If we don't have generics, we do not need to generate a child scope
|
|
|
|
// for the generic bindings to live on.
|
|
|
|
if (hasGenerics)
|
|
|
|
{
|
2022-08-18 22:32:08 +01:00
|
|
|
signatureScope = childScope(fn, scope);
|
2022-07-01 00:52:43 +01:00
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
std::vector<std::pair<Name, GenericTypeDefinition>> genericDefinitions = createGenerics(signatureScope, fn->generics);
|
|
|
|
std::vector<std::pair<Name, GenericTypePackDefinition>> genericPackDefinitions = createGenericPacks(signatureScope, fn->genericPacks);
|
2022-06-24 02:56:00 +01:00
|
|
|
|
2022-07-01 00:52:43 +01:00
|
|
|
for (const auto& [name, g] : genericDefinitions)
|
|
|
|
{
|
|
|
|
genericTypes.push_back(g.ty);
|
2022-08-11 22:01:33 +01:00
|
|
|
signatureScope->privateTypeBindings[name] = TypeFun{g.ty};
|
2022-07-01 00:52:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto& [name, g] : genericPackDefinitions)
|
|
|
|
{
|
|
|
|
genericTypePacks.push_back(g.tp);
|
2022-08-11 22:01:33 +01:00
|
|
|
signatureScope->privateTypePackBindings[name] = g.tp;
|
2022-07-01 00:52:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// To eliminate the need to branch on hasGenerics below, we say that
|
|
|
|
// the signature scope is the parent scope if we don't have
|
|
|
|
// generics.
|
2022-07-29 05:24:07 +01:00
|
|
|
signatureScope = scope;
|
2022-07-01 00:52:43 +01:00
|
|
|
}
|
|
|
|
|
2023-01-20 20:27:03 +00:00
|
|
|
TypePackId argTypes = resolveTypePack(signatureScope, fn->argTypes, inTypeArguments);
|
|
|
|
TypePackId returnTypes = resolveTypePack(signatureScope, fn->returnTypes, inTypeArguments);
|
2022-07-01 00:52:43 +01:00
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
// TODO: FunctionType needs a pointer to the scope so that we know
|
2022-07-01 00:52:43 +01:00
|
|
|
// how to quantify/instantiate it.
|
2023-01-04 20:53:17 +00:00
|
|
|
FunctionType ftv{TypeLevel{}, scope.get(), {}, {}, argTypes, returnTypes};
|
2022-07-01 00:52:43 +01:00
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
// This replicates the behavior of the appropriate FunctionType
|
2022-07-01 00:52:43 +01:00
|
|
|
// constructors.
|
|
|
|
ftv.hasNoGenerics = !hasGenerics;
|
|
|
|
ftv.generics = std::move(genericTypes);
|
|
|
|
ftv.genericPacks = std::move(genericTypePacks);
|
|
|
|
|
|
|
|
ftv.argNames.reserve(fn->argNames.size);
|
2022-06-24 02:56:00 +01:00
|
|
|
for (const auto& el : fn->argNames)
|
|
|
|
{
|
|
|
|
if (el)
|
|
|
|
{
|
|
|
|
const auto& [name, location] = *el;
|
2022-07-01 00:52:43 +01:00
|
|
|
ftv.argNames.push_back(FunctionArgument{name.value, location});
|
2022-06-24 02:56:00 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-07-01 00:52:43 +01:00
|
|
|
ftv.argNames.push_back(std::nullopt);
|
2022-06-24 02:56:00 +01:00
|
|
|
}
|
|
|
|
}
|
2022-07-01 00:52:43 +01:00
|
|
|
|
|
|
|
result = arena->addType(std::move(ftv));
|
2022-06-24 02:56:00 +01:00
|
|
|
}
|
|
|
|
else if (auto tof = ty->as<AstTypeTypeof>())
|
|
|
|
{
|
|
|
|
// TODO: Recursion limit.
|
2022-10-28 11:37:29 +01:00
|
|
|
TypeId exprType = check(scope, tof->expr).ty;
|
2022-06-24 02:56:00 +01:00
|
|
|
result = exprType;
|
|
|
|
}
|
|
|
|
else if (auto unionAnnotation = ty->as<AstTypeUnion>())
|
|
|
|
{
|
|
|
|
std::vector<TypeId> parts;
|
|
|
|
for (AstType* part : unionAnnotation->types)
|
|
|
|
{
|
|
|
|
// TODO: Recursion limit.
|
2023-01-20 20:27:03 +00:00
|
|
|
parts.push_back(resolveType(scope, part, inTypeArguments));
|
2022-06-24 02:56:00 +01:00
|
|
|
}
|
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
result = arena->addType(UnionType{parts});
|
2022-06-24 02:56:00 +01:00
|
|
|
}
|
|
|
|
else if (auto intersectionAnnotation = ty->as<AstTypeIntersection>())
|
|
|
|
{
|
|
|
|
std::vector<TypeId> parts;
|
|
|
|
for (AstType* part : intersectionAnnotation->types)
|
|
|
|
{
|
|
|
|
// TODO: Recursion limit.
|
2023-01-20 20:27:03 +00:00
|
|
|
parts.push_back(resolveType(scope, part, inTypeArguments));
|
2022-06-24 02:56:00 +01:00
|
|
|
}
|
|
|
|
|
2023-01-04 20:53:17 +00:00
|
|
|
result = arena->addType(IntersectionType{parts});
|
2022-06-24 02:56:00 +01:00
|
|
|
}
|
|
|
|
else if (auto boolAnnotation = ty->as<AstTypeSingletonBool>())
|
|
|
|
{
|
2023-01-04 20:53:17 +00:00
|
|
|
result = arena->addType(SingletonType(BooleanSingleton{boolAnnotation->value}));
|
2022-06-24 02:56:00 +01:00
|
|
|
}
|
|
|
|
else if (auto stringAnnotation = ty->as<AstTypeSingletonString>())
|
|
|
|
{
|
2023-01-04 20:53:17 +00:00
|
|
|
result = arena->addType(SingletonType(StringSingleton{std::string(stringAnnotation->value.data, stringAnnotation->value.size)}));
|
2022-06-24 02:56:00 +01:00
|
|
|
}
|
|
|
|
else if (ty->is<AstTypeError>())
|
|
|
|
{
|
2023-01-04 20:53:17 +00:00
|
|
|
result = builtinTypes->errorRecoveryType();
|
2022-06-24 02:56:00 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LUAU_ASSERT(0);
|
2023-01-04 20:53:17 +00:00
|
|
|
result = builtinTypes->errorRecoveryType();
|
2022-06-24 02:56:00 +01:00
|
|
|
}
|
|
|
|
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
module->astResolvedTypes[ty] = result;
|
2022-06-24 02:56:00 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-01-20 20:27:03 +00:00
|
|
|
TypePackId ConstraintGraphBuilder::resolveTypePack(const ScopePtr& scope, AstTypePack* tp, bool inTypeArgument)
|
2022-06-24 02:56:00 +01:00
|
|
|
{
|
|
|
|
TypePackId result;
|
|
|
|
if (auto expl = tp->as<AstTypePackExplicit>())
|
|
|
|
{
|
2023-01-20 20:27:03 +00:00
|
|
|
result = resolveTypePack(scope, expl->typeList, inTypeArgument);
|
2022-06-24 02:56:00 +01:00
|
|
|
}
|
|
|
|
else if (auto var = tp->as<AstTypePackVariadic>())
|
|
|
|
{
|
2023-01-20 20:27:03 +00:00
|
|
|
TypeId ty = resolveType(scope, var->variadicType, inTypeArgument);
|
2023-02-17 23:41:51 +00:00
|
|
|
if (get<ErrorType>(follow(ty)))
|
|
|
|
ty = freshType(scope);
|
2022-06-24 02:56:00 +01:00
|
|
|
result = arena->addTypePack(TypePackVar{VariadicTypePack{ty}});
|
|
|
|
}
|
|
|
|
else if (auto gen = tp->as<AstTypePackGeneric>())
|
|
|
|
{
|
2022-08-11 22:01:33 +01:00
|
|
|
if (std::optional<TypePackId> lookup = scope->lookupPack(gen->genericName.value))
|
2022-08-04 23:35:33 +01:00
|
|
|
{
|
|
|
|
result = *lookup;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
reportError(tp->location, UnknownSymbol{gen->genericName.value, UnknownSymbol::Context::Type});
|
2023-01-04 20:53:17 +00:00
|
|
|
result = builtinTypes->errorRecoveryTypePack();
|
2022-08-04 23:35:33 +01:00
|
|
|
}
|
2022-06-24 02:56:00 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LUAU_ASSERT(0);
|
2023-01-04 20:53:17 +00:00
|
|
|
result = builtinTypes->errorRecoveryTypePack();
|
2022-06-24 02:56:00 +01:00
|
|
|
}
|
|
|
|
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
module->astResolvedTypePacks[tp] = result;
|
2022-06-24 02:56:00 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-01-20 20:27:03 +00:00
|
|
|
TypePackId ConstraintGraphBuilder::resolveTypePack(const ScopePtr& scope, const AstTypeList& list, bool inTypeArguments)
|
2022-06-24 02:56:00 +01:00
|
|
|
{
|
|
|
|
std::vector<TypeId> head;
|
|
|
|
|
|
|
|
for (AstType* headTy : list.types)
|
|
|
|
{
|
2023-01-20 20:27:03 +00:00
|
|
|
head.push_back(resolveType(scope, headTy, inTypeArguments));
|
2022-06-24 02:56:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
std::optional<TypePackId> tail = std::nullopt;
|
|
|
|
if (list.tailType)
|
|
|
|
{
|
2023-01-20 20:27:03 +00:00
|
|
|
tail = resolveTypePack(scope, list.tailType, inTypeArguments);
|
2022-06-24 02:56:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return arena->addTypePack(TypePack{head, tail});
|
2022-06-03 23:15:45 +01:00
|
|
|
}
|
|
|
|
|
2023-02-17 23:41:51 +00:00
|
|
|
std::vector<std::pair<Name, GenericTypeDefinition>> ConstraintGraphBuilder::createGenerics(
|
|
|
|
const ScopePtr& scope, AstArray<AstGenericType> generics, bool useCache)
|
2022-07-01 00:52:43 +01:00
|
|
|
{
|
|
|
|
std::vector<std::pair<Name, GenericTypeDefinition>> result;
|
|
|
|
for (const auto& generic : generics)
|
|
|
|
{
|
2023-02-17 23:41:51 +00:00
|
|
|
TypeId genericTy = nullptr;
|
|
|
|
|
|
|
|
if (auto it = scope->parent->typeAliasTypeParameters.find(generic.name.value); useCache && it != scope->parent->typeAliasTypeParameters.end())
|
|
|
|
genericTy = it->second;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
genericTy = arena->addType(GenericType{scope.get(), generic.name.value});
|
|
|
|
scope->parent->typeAliasTypeParameters[generic.name.value] = genericTy;
|
|
|
|
}
|
|
|
|
|
2022-07-01 00:52:43 +01:00
|
|
|
std::optional<TypeId> defaultTy = std::nullopt;
|
|
|
|
|
|
|
|
if (generic.defaultValue)
|
2023-01-20 20:27:03 +00:00
|
|
|
defaultTy = resolveType(scope, generic.defaultValue, /* inTypeArguments */ false);
|
2022-07-01 00:52:43 +01:00
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
result.push_back({generic.name.value, GenericTypeDefinition{genericTy, defaultTy}});
|
2022-07-01 00:52:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::pair<Name, GenericTypePackDefinition>> ConstraintGraphBuilder::createGenericPacks(
|
2023-02-17 23:41:51 +00:00
|
|
|
const ScopePtr& scope, AstArray<AstGenericTypePack> generics, bool useCache)
|
2022-07-01 00:52:43 +01:00
|
|
|
{
|
|
|
|
std::vector<std::pair<Name, GenericTypePackDefinition>> result;
|
|
|
|
for (const auto& generic : generics)
|
|
|
|
{
|
2023-02-17 23:41:51 +00:00
|
|
|
TypePackId genericTy;
|
|
|
|
|
|
|
|
if (auto it = scope->parent->typeAliasTypePackParameters.find(generic.name.value);
|
|
|
|
useCache && it != scope->parent->typeAliasTypePackParameters.end())
|
|
|
|
genericTy = it->second;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
genericTy = arena->addTypePack(TypePackVar{GenericTypePack{scope.get(), generic.name.value}});
|
|
|
|
scope->parent->typeAliasTypePackParameters[generic.name.value] = genericTy;
|
|
|
|
}
|
|
|
|
|
2022-07-01 00:52:43 +01:00
|
|
|
std::optional<TypePackId> defaultTy = std::nullopt;
|
|
|
|
|
|
|
|
if (generic.defaultValue)
|
2023-01-20 20:27:03 +00:00
|
|
|
defaultTy = resolveTypePack(scope, generic.defaultValue, /* inTypeArguments */ false);
|
2022-07-01 00:52:43 +01:00
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
result.push_back({generic.name.value, GenericTypePackDefinition{genericTy, defaultTy}});
|
2022-07-01 00:52:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-10-28 11:37:29 +01:00
|
|
|
Inference ConstraintGraphBuilder::flattenPack(const ScopePtr& scope, Location location, InferencePack pack)
|
2022-07-01 00:52:43 +01:00
|
|
|
{
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
const auto& [tp, refinements] = pack;
|
|
|
|
RefinementId refinement = nullptr;
|
|
|
|
if (!refinements.empty())
|
|
|
|
refinement = refinements[0];
|
2022-11-04 17:33:22 +00:00
|
|
|
|
2022-07-01 00:52:43 +01:00
|
|
|
if (auto f = first(tp))
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
return Inference{*f, refinement};
|
2022-07-01 00:52:43 +01:00
|
|
|
|
|
|
|
TypeId typeResult = freshType(scope);
|
|
|
|
TypePack onePack{{typeResult}, freshTypePack(scope)};
|
|
|
|
TypePackId oneTypePack = arena->addTypePack(std::move(onePack));
|
|
|
|
|
2022-09-02 00:14:03 +01:00
|
|
|
addConstraint(scope, location, PackSubtypeConstraint{tp, oneTypePack});
|
2022-07-01 00:52:43 +01:00
|
|
|
|
Sync to upstream/release/562 (#828)
* Fixed rare use-after-free in analysis during table unification
A lot of work these past months went into two new Luau components:
* A near full rewrite of the typechecker using a new deferred constraint
resolution system
* Native code generation for AoT/JiT compilation of VM bytecode into x64
(avx)/arm64 instructions
Both of these components are far from finished and we don't provide
documentation on building and using them at this point.
However, curious community members expressed interest in learning about
changes that go into these components each week, so we are now listing
them here in the 'sync' pull request descriptions.
---
New typechecker can be enabled by setting
DebugLuauDeferredConstraintResolution flag to 'true'.
It is considered unstable right now, so try it at your own risk.
Even though it already provides better type inference than the current
one in some cases, our main goal right now is to reach feature parity
with current typechecker.
Features which improve over the capabilities of the current typechecker
are marked as '(NEW)'.
Changes to new typechecker:
* Regular for loop index and parameters are now typechecked
* Invalid type annotations on local variables are ignored to improve
autocomplete
* Fixed missing autocomplete type suggestions for function arguments
* Type reduction is now performed to produce simpler types to be
presented to the user (error messages, custom LSPs)
* Internally, complex types like '((number | string) & ~(false?)) |
string' can be produced, which is just 'string | number' when simplified
* Fixed spots where support for unknown and never types was missing
* (NEW) Length operator '#' is now valid to use on top table type, this
type comes up when doing typeof(x) == "table" guards and isn't available
in current typechecker
---
Changes to native code generation:
* Additional math library fast calls are now lowered to x64: math.ldexp,
math.round, math.frexp, math.modf, math.sign and math.clamp
2023-02-03 19:26:13 +00:00
|
|
|
return Inference{typeResult, refinement};
|
2022-07-01 00:52:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void ConstraintGraphBuilder::reportError(Location location, TypeErrorData err)
|
|
|
|
{
|
|
|
|
errors.push_back(TypeError{location, moduleName, std::move(err)});
|
2022-09-08 23:14:25 +01:00
|
|
|
|
|
|
|
if (FFlag::DebugLuauLogSolverToJson)
|
|
|
|
logger->captureGenerationError(errors.back());
|
2022-07-01 00:52:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void ConstraintGraphBuilder::reportCodeTooComplex(Location location)
|
|
|
|
{
|
|
|
|
errors.push_back(TypeError{location, moduleName, CodeTooComplex{}});
|
2022-09-08 23:14:25 +01:00
|
|
|
|
|
|
|
if (FFlag::DebugLuauLogSolverToJson)
|
|
|
|
logger->captureGenerationError(errors.back());
|
2022-07-01 00:52:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
struct GlobalPrepopulator : AstVisitor
|
|
|
|
{
|
2022-07-29 05:24:07 +01:00
|
|
|
const NotNull<Scope> globalScope;
|
2022-07-01 00:52:43 +01:00
|
|
|
const NotNull<TypeArena> arena;
|
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
GlobalPrepopulator(NotNull<Scope> globalScope, NotNull<TypeArena> arena)
|
2022-07-01 00:52:43 +01:00
|
|
|
: globalScope(globalScope)
|
|
|
|
, arena(arena)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool visit(AstStatFunction* function) override
|
|
|
|
{
|
|
|
|
if (AstExprGlobal* g = function->name->as<AstExprGlobal>())
|
2023-01-04 20:53:17 +00:00
|
|
|
globalScope->bindings[g->name] = Binding{arena->addType(BlockedType{})};
|
2022-07-01 00:52:43 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
void ConstraintGraphBuilder::prepopulateGlobalScope(const ScopePtr& globalScope, AstStatBlock* program)
|
2022-07-01 00:52:43 +01:00
|
|
|
{
|
2022-07-29 05:24:07 +01:00
|
|
|
GlobalPrepopulator gp{NotNull{globalScope.get()}, arena};
|
2022-07-01 00:52:43 +01:00
|
|
|
|
|
|
|
program->visit(&gp);
|
|
|
|
}
|
|
|
|
|
2022-11-10 22:53:13 +00:00
|
|
|
std::vector<NotNull<Constraint>> borrowConstraints(const std::vector<ConstraintPtr>& constraints)
|
2022-06-03 23:15:45 +01:00
|
|
|
{
|
2022-11-10 22:53:13 +00:00
|
|
|
std::vector<NotNull<Constraint>> result;
|
|
|
|
result.reserve(constraints.size());
|
2022-06-03 23:15:45 +01:00
|
|
|
|
2022-11-10 22:53:13 +00:00
|
|
|
for (const auto& c : constraints)
|
|
|
|
result.emplace_back(c.get());
|
2022-06-03 23:15:45 +01:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Luau
|