2021-10-30 04:25:12 +08:00
|
|
|
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "Luau/Error.h"
|
|
|
|
#include "Luau/Location.h"
|
2022-09-09 06:14:25 +08:00
|
|
|
#include "Luau/ParseOptions.h"
|
2022-08-19 05:32:08 +08:00
|
|
|
#include "Luau/Scope.h"
|
2022-09-09 06:14:25 +08:00
|
|
|
#include "Luau/Substitution.h"
|
2021-10-30 04:25:12 +08:00
|
|
|
#include "Luau/TxnLog.h"
|
2022-05-20 08:02:24 +08:00
|
|
|
#include "Luau/TypeArena.h"
|
2021-11-05 23:47:21 +08:00
|
|
|
#include "Luau/UnifierSharedState.h"
|
2022-10-07 08:23:29 +08:00
|
|
|
#include "Normalize.h"
|
2021-10-30 04:25:12 +08:00
|
|
|
|
|
|
|
#include <unordered_set>
|
|
|
|
|
|
|
|
namespace Luau
|
|
|
|
{
|
|
|
|
|
|
|
|
enum Variance
|
|
|
|
{
|
|
|
|
Covariant,
|
|
|
|
Invariant
|
|
|
|
};
|
|
|
|
|
2022-02-25 07:53:37 +08:00
|
|
|
// A substitution which replaces singleton types by their wider types
|
|
|
|
struct Widen : Substitution
|
|
|
|
{
|
2023-01-05 04:53:17 +08:00
|
|
|
Widen(TypeArena* arena, NotNull<BuiltinTypes> builtinTypes)
|
2022-02-25 07:53:37 +08:00
|
|
|
: Substitution(TxnLog::empty(), arena)
|
2023-01-05 04:53:17 +08:00
|
|
|
, builtinTypes(builtinTypes)
|
2022-02-25 07:53:37 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-01-05 04:53:17 +08:00
|
|
|
NotNull<BuiltinTypes> builtinTypes;
|
2022-09-09 06:14:25 +08:00
|
|
|
|
2022-02-25 07:53:37 +08:00
|
|
|
bool isDirty(TypeId ty) override;
|
|
|
|
bool isDirty(TypePackId ty) override;
|
|
|
|
TypeId clean(TypeId ty) override;
|
|
|
|
TypePackId clean(TypePackId ty) override;
|
|
|
|
bool ignoreChildren(TypeId ty) override;
|
2022-05-27 06:08:16 +08:00
|
|
|
|
|
|
|
TypeId operator()(TypeId ty);
|
|
|
|
TypePackId operator()(TypePackId ty);
|
2022-02-25 07:53:37 +08:00
|
|
|
};
|
|
|
|
|
2023-07-28 23:13:53 +08:00
|
|
|
/**
|
|
|
|
* Normally, when we unify table properties, we must do so invariantly, but we
|
|
|
|
* can introduce a special exception: If the table property in the subtype
|
|
|
|
* position arises from a literal expression, it is safe to instead perform a
|
|
|
|
* covariant check.
|
|
|
|
*
|
|
|
|
* This is very useful for typechecking cases where table literals (and trees of
|
|
|
|
* table literals) are passed directly to functions.
|
|
|
|
*
|
|
|
|
* In this case, we know that the property has no other name referring to it and
|
|
|
|
* so it is perfectly safe for the function to mutate the table any way it
|
|
|
|
* wishes.
|
|
|
|
*/
|
|
|
|
using LiteralProperties = DenseHashSet<Name>;
|
|
|
|
|
2022-02-25 07:53:37 +08:00
|
|
|
// TODO: Use this more widely.
|
|
|
|
struct UnifierOptions
|
|
|
|
{
|
|
|
|
bool isFunctionCall = false;
|
|
|
|
};
|
|
|
|
|
2021-10-30 04:25:12 +08:00
|
|
|
struct Unifier
|
|
|
|
{
|
|
|
|
TypeArena* const types;
|
2023-01-05 04:53:17 +08:00
|
|
|
NotNull<BuiltinTypes> builtinTypes;
|
2022-10-07 08:23:29 +08:00
|
|
|
NotNull<Normalizer> normalizer;
|
2021-10-30 04:25:12 +08:00
|
|
|
|
2022-08-19 05:32:08 +08:00
|
|
|
NotNull<Scope> scope; // const Scope maybe
|
2021-10-30 04:25:12 +08:00
|
|
|
TxnLog log;
|
2023-03-18 03:20:37 +08:00
|
|
|
bool failure = false;
|
2021-10-30 04:25:12 +08:00
|
|
|
ErrorVec errors;
|
|
|
|
Location location;
|
|
|
|
Variance variance = Covariant;
|
2023-03-04 04:21:14 +08:00
|
|
|
bool normalize = true; // Normalize unions and intersections if necessary
|
|
|
|
bool checkInhabited = true; // Normalize types to check if they are inhabited
|
2021-10-30 04:25:12 +08:00
|
|
|
CountMismatch::Context ctx = CountMismatch::Arg;
|
|
|
|
|
2023-05-13 01:50:47 +08:00
|
|
|
// If true, generics act as free types when unifying.
|
|
|
|
bool hideousFixMeGenericsAreActuallyFree = false;
|
|
|
|
|
2021-11-05 23:47:21 +08:00
|
|
|
UnifierSharedState& sharedState;
|
2021-10-30 04:25:12 +08:00
|
|
|
|
2023-02-25 05:49:38 +08:00
|
|
|
// When the Unifier is forced to unify two blocked types (or packs), they
|
|
|
|
// get added to these vectors. The ConstraintSolver can use this to know
|
|
|
|
// when it is safe to reattempt dispatching a constraint.
|
|
|
|
std::vector<TypeId> blockedTypes;
|
|
|
|
std::vector<TypePackId> blockedTypePacks;
|
|
|
|
|
2023-07-15 02:08:53 +08:00
|
|
|
Unifier(NotNull<Normalizer> normalizer, NotNull<Scope> scope, const Location& location, Variance variance, TxnLog* parentLog = nullptr);
|
2021-10-30 04:25:12 +08:00
|
|
|
|
2023-05-13 01:50:47 +08:00
|
|
|
// Configure the Unifier to test for scope subsumption via embedded Scope
|
|
|
|
// pointers rather than TypeLevels.
|
2023-07-28 23:13:53 +08:00
|
|
|
void enableNewSolver();
|
2023-05-13 01:50:47 +08:00
|
|
|
|
2021-10-30 04:25:12 +08:00
|
|
|
// Test whether the two type vars unify. Never commits the result.
|
2022-01-07 09:46:53 +08:00
|
|
|
ErrorVec canUnify(TypeId subTy, TypeId superTy);
|
|
|
|
ErrorVec canUnify(TypePackId subTy, TypePackId superTy, bool isFunctionCall = false);
|
2021-10-30 04:25:12 +08:00
|
|
|
|
2022-01-07 09:46:53 +08:00
|
|
|
/** Attempt to unify.
|
2021-10-30 04:25:12 +08:00
|
|
|
* Populate the vector errors with any type errors that may arise.
|
|
|
|
* Populate the transaction log with the set of TypeIds that need to be reset to undo the unification attempt.
|
|
|
|
*/
|
2023-07-28 23:13:53 +08:00
|
|
|
void tryUnify(TypeId subTy, TypeId superTy, bool isFunctionCall = false, bool isIntersection = false, const LiteralProperties* aliasableMap = nullptr);
|
2021-10-30 04:25:12 +08:00
|
|
|
|
|
|
|
private:
|
2023-07-28 23:13:53 +08:00
|
|
|
void tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall = false, bool isIntersection = false, const LiteralProperties* aliasableMap = nullptr);
|
2023-01-05 04:53:17 +08:00
|
|
|
void tryUnifyUnionWithType(TypeId subTy, const UnionType* uv, TypeId superTy);
|
2023-03-11 04:21:07 +08:00
|
|
|
|
|
|
|
// Traverse the two types provided and block on any BlockedTypes we find.
|
|
|
|
// Returns true if any types were blocked on.
|
2023-03-18 03:20:37 +08:00
|
|
|
bool DEPRECATED_blockOnBlockedTypes(TypeId subTy, TypeId superTy);
|
2023-03-11 04:21:07 +08:00
|
|
|
|
2023-01-05 04:53:17 +08:00
|
|
|
void tryUnifyTypeWithUnion(TypeId subTy, TypeId superTy, const UnionType* uv, bool cacheEnabled, bool isFunctionCall);
|
|
|
|
void tryUnifyTypeWithIntersection(TypeId subTy, TypeId superTy, const IntersectionType* uv);
|
|
|
|
void tryUnifyIntersectionWithType(TypeId subTy, const IntersectionType* uv, TypeId superTy, bool cacheEnabled, bool isFunctionCall);
|
2022-10-15 03:48:41 +08:00
|
|
|
void tryUnifyNormalizedTypes(TypeId subTy, TypeId superTy, const NormalizedType& subNorm, const NormalizedType& superNorm, std::string reason,
|
|
|
|
std::optional<TypeError> error = std::nullopt);
|
2022-01-07 09:46:53 +08:00
|
|
|
void tryUnifyPrimitives(TypeId subTy, TypeId superTy);
|
|
|
|
void tryUnifySingletons(TypeId subTy, TypeId superTy);
|
|
|
|
void tryUnifyFunctions(TypeId subTy, TypeId superTy, bool isFunctionCall = false);
|
2023-07-28 23:13:53 +08:00
|
|
|
void tryUnifyTables(TypeId subTy, TypeId superTy, bool isIntersection = false, const LiteralProperties* aliasableMap = nullptr);
|
2022-07-15 06:52:26 +08:00
|
|
|
void tryUnifyScalarShape(TypeId subTy, TypeId superTy, bool reversed);
|
2022-01-07 09:46:53 +08:00
|
|
|
void tryUnifyWithMetatable(TypeId subTy, TypeId superTy, bool reversed);
|
|
|
|
void tryUnifyWithClass(TypeId subTy, TypeId superTy, bool reversed);
|
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-04 03:26:13 +08:00
|
|
|
void tryUnifyNegations(TypeId subTy, TypeId superTy);
|
2022-02-25 07:53:37 +08:00
|
|
|
|
2022-10-07 08:23:29 +08:00
|
|
|
TypePackId tryApplyOverloadedFunction(TypeId function, const NormalizedFunctionType& overloads, TypePackId args);
|
|
|
|
|
2022-02-25 07:53:37 +08:00
|
|
|
TypeId widen(TypeId ty);
|
2022-03-18 08:46:04 +08:00
|
|
|
TypePackId widen(TypePackId tp);
|
|
|
|
|
2021-11-05 23:47:21 +08:00
|
|
|
TypeId deeplyOptional(TypeId ty, std::unordered_map<TypeId, TypeId> seen = {});
|
2022-02-25 07:53:37 +08:00
|
|
|
|
2022-03-25 06:04:14 +08:00
|
|
|
bool canCacheResult(TypeId subTy, TypeId superTy);
|
|
|
|
void cacheResult(TypeId subTy, TypeId superTy, size_t prevErrorCount);
|
2021-10-30 04:25:12 +08:00
|
|
|
|
|
|
|
public:
|
2022-01-07 09:46:53 +08:00
|
|
|
void tryUnify(TypePackId subTy, TypePackId superTy, bool isFunctionCall = false);
|
2021-10-30 04:25:12 +08:00
|
|
|
|
|
|
|
private:
|
2022-01-07 09:46:53 +08:00
|
|
|
void tryUnify_(TypePackId subTy, TypePackId superTy, bool isFunctionCall = false);
|
|
|
|
void tryUnifyVariadics(TypePackId subTy, TypePackId superTy, bool reversed, int subOffset = 0);
|
2021-10-30 04:25:12 +08:00
|
|
|
|
2022-01-07 09:46:53 +08:00
|
|
|
void tryUnifyWithAny(TypeId subTy, TypeId anyTy);
|
|
|
|
void tryUnifyWithAny(TypePackId subTy, TypePackId anyTp);
|
2021-10-30 04:25:12 +08:00
|
|
|
|
|
|
|
std::optional<TypeId> findTablePropertyRespectingMeta(TypeId lhsType, Name name);
|
|
|
|
|
2022-12-03 02:09:59 +08:00
|
|
|
TxnLog combineLogsIntoIntersection(std::vector<TxnLog> logs);
|
|
|
|
TxnLog combineLogsIntoUnion(std::vector<TxnLog> logs);
|
|
|
|
|
2021-10-30 04:25:12 +08:00
|
|
|
public:
|
2022-08-12 05:01:33 +08:00
|
|
|
// Returns true if the type "needle" already occurs within "haystack" and reports an "infinite type error"
|
2023-04-15 02:06:22 +08:00
|
|
|
bool occursCheck(TypeId needle, TypeId haystack, bool reversed);
|
2022-08-12 05:01:33 +08:00
|
|
|
bool occursCheck(DenseHashSet<TypeId>& seen, TypeId needle, TypeId haystack);
|
2023-04-15 02:06:22 +08:00
|
|
|
bool occursCheck(TypePackId needle, TypePackId haystack, bool reversed);
|
2022-08-12 05:01:33 +08:00
|
|
|
bool occursCheck(DenseHashSet<TypePackId>& seen, TypePackId needle, TypePackId haystack);
|
2021-10-30 04:25:12 +08:00
|
|
|
|
|
|
|
Unifier makeChildUnifier();
|
|
|
|
|
2022-04-15 07:57:43 +08:00
|
|
|
void reportError(TypeError err);
|
2022-11-05 01:33:22 +08:00
|
|
|
LUAU_NOINLINE void reportError(Location location, TypeErrorData data);
|
2022-01-28 07:46:05 +08:00
|
|
|
|
2021-10-30 04:25:12 +08:00
|
|
|
private:
|
2022-12-03 02:09:59 +08:00
|
|
|
TypeMismatch::Context mismatchContext();
|
2021-10-30 04:25:12 +08:00
|
|
|
|
|
|
|
void checkChildUnifierTypeMismatch(const ErrorVec& innerErrors, TypeId wantedType, TypeId givenType);
|
2021-11-12 22:27:34 +08:00
|
|
|
void checkChildUnifierTypeMismatch(const ErrorVec& innerErrors, const std::string& prop, TypeId wantedType, TypeId givenType);
|
2021-10-30 04:25:12 +08:00
|
|
|
|
|
|
|
[[noreturn]] void ice(const std::string& message, const Location& location);
|
|
|
|
[[noreturn]] void ice(const std::string& message);
|
2021-12-11 06:05:05 +08:00
|
|
|
|
|
|
|
// Available after regular type pack unification errors
|
|
|
|
std::optional<int> firstPackErrorPos;
|
2023-05-13 01:50:47 +08:00
|
|
|
|
2023-07-28 23:13:53 +08:00
|
|
|
// If true, we do a bunch of small things differently to work better with
|
|
|
|
// the new type inference engine. Most notably, we use the Scope hierarchy
|
|
|
|
// directly rather than using TypeLevels.
|
|
|
|
bool useNewSolver = false;
|
2021-10-30 04:25:12 +08:00
|
|
|
};
|
|
|
|
|
2022-09-30 06:23:10 +08:00
|
|
|
void promoteTypeLevels(TxnLog& log, const TypeArena* arena, TypeLevel minLevel, Scope* outerScope, bool useScope, TypePackId tp);
|
2023-03-04 04:21:14 +08:00
|
|
|
std::optional<TypeError> hasUnificationTooComplex(const ErrorVec& errors);
|
2023-05-06 05:52:49 +08:00
|
|
|
std::optional<TypeError> hasCountMismatch(const ErrorVec& errors);
|
2022-04-15 07:57:43 +08:00
|
|
|
|
2021-10-30 04:25:12 +08:00
|
|
|
} // namespace Luau
|