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-08-19 05:32:08 +08:00
|
|
|
#include "Luau/Scope.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"
|
2022-08-19 05:32:08 +08:00
|
|
|
#include "Luau/TypeInfer.h"
|
2021-11-05 23:47:21 +08:00
|
|
|
#include "Luau/UnifierSharedState.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
|
|
|
|
{
|
|
|
|
Widen(TypeArena* arena)
|
|
|
|
: Substitution(TxnLog::empty(), arena)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
};
|
|
|
|
|
|
|
|
// TODO: Use this more widely.
|
|
|
|
struct UnifierOptions
|
|
|
|
{
|
|
|
|
bool isFunctionCall = false;
|
|
|
|
};
|
|
|
|
|
2021-10-30 04:25:12 +08:00
|
|
|
struct Unifier
|
|
|
|
{
|
|
|
|
TypeArena* const types;
|
|
|
|
Mode mode;
|
|
|
|
|
2022-08-19 05:32:08 +08:00
|
|
|
NotNull<Scope> scope; // const Scope maybe
|
2021-10-30 04:25:12 +08:00
|
|
|
TxnLog log;
|
|
|
|
ErrorVec errors;
|
|
|
|
Location location;
|
|
|
|
Variance variance = Covariant;
|
2022-04-15 07:57:43 +08:00
|
|
|
bool anyIsTop = false; // If true, we consider any to be a top type. If false, it is a familiar but weird mix of top and bottom all at once.
|
2021-10-30 04:25:12 +08:00
|
|
|
CountMismatch::Context ctx = CountMismatch::Arg;
|
|
|
|
|
2021-11-05 23:47:21 +08:00
|
|
|
UnifierSharedState& sharedState;
|
2021-10-30 04:25:12 +08:00
|
|
|
|
2022-08-19 05:32:08 +08:00
|
|
|
Unifier(TypeArena* types, Mode mode, NotNull<Scope> scope, const Location& location, Variance variance, UnifierSharedState& sharedState, TxnLog* parentLog = nullptr);
|
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.
|
|
|
|
*/
|
2022-01-07 09:46:53 +08:00
|
|
|
void tryUnify(TypeId subTy, TypeId superTy, bool isFunctionCall = false, bool isIntersection = false);
|
2021-10-30 04:25:12 +08:00
|
|
|
|
|
|
|
private:
|
2022-01-07 09:46:53 +08:00
|
|
|
void tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall = false, bool isIntersection = false);
|
2022-02-05 00:45:57 +08:00
|
|
|
void tryUnifyUnionWithType(TypeId subTy, const UnionTypeVar* uv, TypeId superTy);
|
|
|
|
void tryUnifyTypeWithUnion(TypeId subTy, TypeId superTy, const UnionTypeVar* uv, bool cacheEnabled, bool isFunctionCall);
|
|
|
|
void tryUnifyTypeWithIntersection(TypeId subTy, TypeId superTy, const IntersectionTypeVar* uv);
|
|
|
|
void tryUnifyIntersectionWithType(TypeId subTy, const IntersectionTypeVar* uv, TypeId superTy, bool cacheEnabled, bool isFunctionCall);
|
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);
|
|
|
|
void tryUnifyTables(TypeId subTy, TypeId superTy, bool isIntersection = false);
|
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);
|
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-04-15 07:57:43 +08:00
|
|
|
void tryUnifyWithConstrainedSubTypeVar(TypeId subTy, TypeId superTy);
|
|
|
|
void tryUnifyWithConstrainedSuperTypeVar(TypeId subTy, TypeId superTy);
|
|
|
|
|
2021-10-30 04:25:12 +08:00
|
|
|
public:
|
2022-06-17 09:05:14 +08:00
|
|
|
void unifyLowerBound(TypePackId subTy, TypePackId superTy, TypeLevel demotedLevel);
|
2022-04-15 07:57:43 +08:00
|
|
|
|
2022-08-12 05:01:33 +08:00
|
|
|
// Returns true if the type "needle" already occurs within "haystack" and reports an "infinite type error"
|
|
|
|
bool occursCheck(TypeId needle, TypeId haystack);
|
|
|
|
bool occursCheck(DenseHashSet<TypeId>& seen, TypeId needle, TypeId haystack);
|
|
|
|
bool occursCheck(TypePackId needle, TypePackId haystack);
|
|
|
|
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-01-28 07:46:05 +08:00
|
|
|
|
2021-10-30 04:25:12 +08:00
|
|
|
private:
|
|
|
|
bool isNonstrictMode() const;
|
|
|
|
|
|
|
|
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;
|
2021-10-30 04:25:12 +08:00
|
|
|
};
|
|
|
|
|
2022-04-15 07:57:43 +08:00
|
|
|
void promoteTypeLevels(TxnLog& log, const TypeArena* arena, TypeLevel minLevel, TypePackId tp);
|
|
|
|
|
2021-10-30 04:25:12 +08:00
|
|
|
} // namespace Luau
|