luau/Analysis/include/Luau/Unifiable.h

151 lines
3.6 KiB
C
Raw Normal View History

// 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 04:41:13 +01:00
struct Scope;
2022-06-03 21:32:20 +01:00
/**
2023-01-03 17:33:19 +00:00
* The 'level' of a Type is an indirect way to talk about the scope that it 'belongs' too.
* 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;
// Returns true if the level of "this" belongs to an equal or larger scope than that of rhs
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;
}
// 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);
}
TypeLevel incr() const
{
TypeLevel result;
result.level = level + 1;
result.subLevel = 0;
return result;
}
};
2022-04-14 22:57:15 +01:00
inline TypeLevel max(const TypeLevel& a, const TypeLevel& b)
{
if (a.subsumes(b))
return b;
else
return a;
}
inline TypeLevel min(const TypeLevel& a, const TypeLevel& b)
{
if (a.subsumes(b))
return a;
else
return b;
}
2022-04-14 22:57:15 +01:00
} // namespace Luau
namespace Luau::Unifiable
{
using Name = std::string;
2023-03-17 14:59:30 +00:00
int freshIndex();
struct Free
{
explicit Free(TypeLevel level);
2022-07-29 04:41:13 +01:00
explicit Free(Scope* scope);
2022-09-29 23:11:54 +01:00
explicit Free(Scope* scope, TypeLevel level);
int index;
TypeLevel level;
2022-07-29 04:41:13 +01:00
Scope* scope = nullptr;
// True if this free type variable is part of a mutually
// recursive type alias whose definitions haven't been
// resolved yet.
bool forwardedTypeAlias = false;
private:
2022-10-07 00:55:58 +01:00
static int DEPRECATED_nextIndex;
};
template<typename Id>
struct Bound
{
explicit Bound(Id boundTo)
: boundTo(boundTo)
{
}
Id boundTo;
};
struct Generic
{
// By default, generics are global, with a synthetic name
Generic();
explicit Generic(TypeLevel level);
explicit Generic(const Name& name);
2022-07-29 04:41:13 +01:00
explicit Generic(Scope* scope);
Generic(TypeLevel level, const Name& name);
2022-07-29 04:41:13 +01:00
Generic(Scope* scope, const Name& name);
int index;
TypeLevel level;
2022-07-29 04:41:13 +01:00
Scope* scope = nullptr;
Name name;
2022-06-03 21:32:20 +01:00
bool explicitName = false;
private:
2022-10-07 00:55:58 +01:00
static int DEPRECATED_nextIndex;
};
struct Error
{
2023-01-03 17:33:19 +00:00
// This constructor has to be public, since it's used in Type and TypePack,
2021-11-18 22:21:07 +00:00
// but shouldn't be called directly. Please use errorRecoveryType() instead.
Error();
int index;
private:
static int nextIndex;
};
template<typename Id, typename... Value>
2022-04-14 22:57:15 +01:00
using Variant = Luau::Variant<Free, Bound<Id>, Generic, Error, Value...>;
2022-04-14 22:57:15 +01:00
} // namespace Luau::Unifiable