2021-10-29 21:25:12 +01: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/Variant.h"
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
namespace Luau
|
|
|
|
{
|
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
struct Scope;
|
2022-06-03 23:15:45 +01:00
|
|
|
|
2021-10-29 21:25:12 +01:00
|
|
|
/**
|
2023-01-04 20:53:17 +00:00
|
|
|
* The 'level' of a Type is an indirect way to talk about the scope that it 'belongs' too.
|
2021-10-29 21:25:12 +01:00
|
|
|
* To start, read http://okmij.org/ftp/ML/generalization.html
|
|
|
|
*
|
|
|
|
* We extend the idea by adding a "sub-level" which helps us to differentiate sibling scopes
|
|
|
|
* within a single larger scope.
|
|
|
|
*
|
|
|
|
* We need this because we try to prototype functions and add them to the type environment before
|
|
|
|
* we check the function bodies. This allows us to properly typecheck many scenarios where there
|
|
|
|
* is no single good order in which to typecheck a program.
|
|
|
|
*/
|
|
|
|
struct TypeLevel
|
|
|
|
{
|
|
|
|
int level = 0;
|
|
|
|
int subLevel = 0;
|
|
|
|
|
2021-12-10 22:05:05 +00:00
|
|
|
// Returns true if the level of "this" belongs to an equal or larger scope than that of rhs
|
2021-10-29 21:25:12 +01:00
|
|
|
bool subsumes(const TypeLevel& rhs) const
|
|
|
|
{
|
|
|
|
if (level < rhs.level)
|
|
|
|
return true;
|
|
|
|
if (level > rhs.level)
|
|
|
|
return false;
|
|
|
|
if (subLevel == rhs.subLevel)
|
|
|
|
return true; // if level == rhs.level and subLevel == rhs.subLevel, then they are the exact same TypeLevel
|
|
|
|
|
|
|
|
// Sibling TypeLevels (that is, TypeLevels that share a level but have a different subLevel) are not considered to subsume one another
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-12-10 22:05:05 +00:00
|
|
|
// Returns true if the level of "this" belongs to a larger (not equal) scope than that of rhs
|
|
|
|
bool subsumesStrict(const TypeLevel& rhs) const
|
|
|
|
{
|
|
|
|
if (level == rhs.level && subLevel == rhs.subLevel)
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
return subsumes(rhs);
|
|
|
|
}
|
|
|
|
|
2021-10-29 21:25:12 +01:00
|
|
|
TypeLevel incr() const
|
|
|
|
{
|
|
|
|
TypeLevel result;
|
|
|
|
result.level = level + 1;
|
|
|
|
result.subLevel = 0;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-04-15 00:57:43 +01:00
|
|
|
inline TypeLevel max(const TypeLevel& a, const TypeLevel& b)
|
|
|
|
{
|
|
|
|
if (a.subsumes(b))
|
|
|
|
return b;
|
|
|
|
else
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
2021-10-29 21:25:12 +01:00
|
|
|
inline TypeLevel min(const TypeLevel& a, const TypeLevel& b)
|
|
|
|
{
|
|
|
|
if (a.subsumes(b))
|
|
|
|
return a;
|
|
|
|
else
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
2022-04-15 00:57:43 +01:00
|
|
|
} // namespace Luau
|
|
|
|
|
|
|
|
namespace Luau::Unifiable
|
2021-10-29 21:25:12 +01:00
|
|
|
{
|
|
|
|
|
|
|
|
using Name = std::string;
|
|
|
|
|
2023-03-17 19:20:37 +00:00
|
|
|
int freshIndex();
|
2023-03-24 18:03:04 +00:00
|
|
|
|
2021-10-29 21:25:12 +01:00
|
|
|
template<typename Id>
|
|
|
|
struct Bound
|
|
|
|
{
|
|
|
|
explicit Bound(Id boundTo)
|
|
|
|
: boundTo(boundTo)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Id boundTo;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Error
|
|
|
|
{
|
2023-01-04 20:53:17 +00:00
|
|
|
// This constructor has to be public, since it's used in Type and TypePack,
|
2021-11-19 16:10:07 +00:00
|
|
|
// but shouldn't be called directly. Please use errorRecoveryType() instead.
|
2021-10-29 21:25:12 +01:00
|
|
|
Error();
|
|
|
|
|
|
|
|
int index;
|
|
|
|
|
|
|
|
private:
|
|
|
|
static int nextIndex;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename Id, typename... Value>
|
2023-04-07 22:01:29 +01:00
|
|
|
using Variant = Luau::Variant<Bound<Id>, Error, Value...>;
|
2021-10-29 21:25:12 +01:00
|
|
|
|
2022-04-15 00:57:43 +01:00
|
|
|
} // namespace Luau::Unifiable
|