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
|
|
|
|
#include "Luau/Module.h"
|
|
|
|
|
2022-04-07 22:29:01 +01:00
|
|
|
#include "Luau/Clone.h"
|
2022-04-15 00:57:43 +01:00
|
|
|
#include "Luau/Common.h"
|
|
|
|
#include "Luau/Normalize.h"
|
2021-12-03 06:41:04 +00:00
|
|
|
#include "Luau/RecursionCounter.h"
|
2021-11-05 02:34:35 +00:00
|
|
|
#include "Luau/Scope.h"
|
2021-10-29 21:25:12 +01:00
|
|
|
#include "Luau/TypeInfer.h"
|
|
|
|
#include "Luau/TypePack.h"
|
|
|
|
#include "Luau/TypeVar.h"
|
|
|
|
#include "Luau/VisitTypeVar.h"
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
LUAU_FASTFLAGVARIABLE(DebugLuauFreezeArena, false)
|
2022-04-15 00:57:43 +01:00
|
|
|
LUAU_FASTFLAG(LuauLowerBoundsCalculation)
|
2022-04-21 22:44:27 +01:00
|
|
|
LUAU_FASTFLAG(LuauLosslessClone)
|
2022-01-27 23:46:05 +00:00
|
|
|
|
2021-10-29 21:25:12 +01:00
|
|
|
namespace Luau
|
|
|
|
{
|
|
|
|
|
|
|
|
static bool contains(Position pos, Comment comment)
|
|
|
|
{
|
|
|
|
if (comment.location.contains(pos))
|
|
|
|
return true;
|
2021-12-10 22:05:05 +00:00
|
|
|
else if (comment.type == Lexeme::BrokenComment &&
|
2021-10-29 21:25:12 +01:00
|
|
|
comment.location.begin <= pos) // Broken comments are broken specifically because they don't have an end
|
|
|
|
return true;
|
|
|
|
else if (comment.type == Lexeme::Comment && comment.location.end == pos)
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isWithinComment(const SourceModule& sourceModule, Position pos)
|
|
|
|
{
|
|
|
|
auto iter = std::lower_bound(sourceModule.commentLocations.begin(), sourceModule.commentLocations.end(),
|
|
|
|
Comment{Lexeme::Comment, Location{pos, pos}}, [](const Comment& a, const Comment& b) {
|
|
|
|
return a.location.end < b.location.end;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (iter == sourceModule.commentLocations.end())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (contains(pos, *iter))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Due to the nature of std::lower_bound, it is possible that iter points at a comment that ends
|
|
|
|
// at pos. We'll try the next comment, if it exists.
|
|
|
|
++iter;
|
|
|
|
if (iter == sourceModule.commentLocations.end())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return contains(pos, *iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TypeArena::clear()
|
|
|
|
{
|
|
|
|
typeVars.clear();
|
|
|
|
typePacks.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
TypeId TypeArena::addTV(TypeVar&& tv)
|
|
|
|
{
|
|
|
|
TypeId allocated = typeVars.allocate(std::move(tv));
|
|
|
|
|
2022-03-24 22:04:14 +00:00
|
|
|
asMutable(allocated)->owningArena = this;
|
2021-10-29 21:25:12 +01:00
|
|
|
|
|
|
|
return allocated;
|
|
|
|
}
|
|
|
|
|
|
|
|
TypeId TypeArena::freshType(TypeLevel level)
|
|
|
|
{
|
|
|
|
TypeId allocated = typeVars.allocate(FreeTypeVar{level});
|
|
|
|
|
2022-03-24 22:04:14 +00:00
|
|
|
asMutable(allocated)->owningArena = this;
|
2021-10-29 21:25:12 +01:00
|
|
|
|
|
|
|
return allocated;
|
|
|
|
}
|
|
|
|
|
|
|
|
TypePackId TypeArena::addTypePack(std::initializer_list<TypeId> types)
|
|
|
|
{
|
|
|
|
TypePackId allocated = typePacks.allocate(TypePack{std::move(types)});
|
|
|
|
|
2022-03-24 22:04:14 +00:00
|
|
|
asMutable(allocated)->owningArena = this;
|
2021-10-29 21:25:12 +01:00
|
|
|
|
|
|
|
return allocated;
|
|
|
|
}
|
|
|
|
|
|
|
|
TypePackId TypeArena::addTypePack(std::vector<TypeId> types)
|
|
|
|
{
|
|
|
|
TypePackId allocated = typePacks.allocate(TypePack{std::move(types)});
|
|
|
|
|
2022-03-24 22:04:14 +00:00
|
|
|
asMutable(allocated)->owningArena = this;
|
2021-10-29 21:25:12 +01:00
|
|
|
|
|
|
|
return allocated;
|
|
|
|
}
|
|
|
|
|
|
|
|
TypePackId TypeArena::addTypePack(TypePack tp)
|
|
|
|
{
|
|
|
|
TypePackId allocated = typePacks.allocate(std::move(tp));
|
|
|
|
|
2022-03-24 22:04:14 +00:00
|
|
|
asMutable(allocated)->owningArena = this;
|
2021-10-29 21:25:12 +01:00
|
|
|
|
|
|
|
return allocated;
|
|
|
|
}
|
|
|
|
|
|
|
|
TypePackId TypeArena::addTypePack(TypePackVar tp)
|
|
|
|
{
|
|
|
|
TypePackId allocated = typePacks.allocate(std::move(tp));
|
|
|
|
|
2022-03-24 22:04:14 +00:00
|
|
|
asMutable(allocated)->owningArena = this;
|
2021-10-29 21:25:12 +01:00
|
|
|
|
|
|
|
return allocated;
|
|
|
|
}
|
|
|
|
|
|
|
|
ScopePtr Module::getModuleScope() const
|
|
|
|
{
|
|
|
|
LUAU_ASSERT(!scopes.empty());
|
|
|
|
return scopes.front().second;
|
|
|
|
}
|
|
|
|
|
|
|
|
void freeze(TypeArena& arena)
|
|
|
|
{
|
|
|
|
if (!FFlag::DebugLuauFreezeArena)
|
|
|
|
return;
|
|
|
|
|
|
|
|
arena.typeVars.freeze();
|
|
|
|
arena.typePacks.freeze();
|
|
|
|
}
|
|
|
|
|
|
|
|
void unfreeze(TypeArena& arena)
|
|
|
|
{
|
|
|
|
if (!FFlag::DebugLuauFreezeArena)
|
|
|
|
return;
|
|
|
|
|
|
|
|
arena.typeVars.unfreeze();
|
|
|
|
arena.typePacks.unfreeze();
|
|
|
|
}
|
|
|
|
|
|
|
|
Module::~Module()
|
|
|
|
{
|
|
|
|
unfreeze(interfaceTypes);
|
|
|
|
unfreeze(internalTypes);
|
|
|
|
}
|
|
|
|
|
2022-04-15 00:57:43 +01:00
|
|
|
bool Module::clonePublicInterface(InternalErrorReporter& ice)
|
2021-10-29 21:25:12 +01:00
|
|
|
{
|
|
|
|
LUAU_ASSERT(interfaceTypes.typeVars.empty());
|
|
|
|
LUAU_ASSERT(interfaceTypes.typePacks.empty());
|
|
|
|
|
2021-12-03 06:41:04 +00:00
|
|
|
CloneState cloneState;
|
2021-10-29 21:25:12 +01:00
|
|
|
|
|
|
|
ScopePtr moduleScope = getModuleScope();
|
|
|
|
|
2022-04-15 00:57:43 +01:00
|
|
|
moduleScope->returnType = clone(moduleScope->returnType, interfaceTypes, cloneState);
|
2021-10-29 21:25:12 +01:00
|
|
|
if (moduleScope->varargPack)
|
2022-04-15 00:57:43 +01:00
|
|
|
moduleScope->varargPack = clone(*moduleScope->varargPack, interfaceTypes, cloneState);
|
|
|
|
|
|
|
|
if (FFlag::LuauLowerBoundsCalculation)
|
|
|
|
{
|
|
|
|
normalize(moduleScope->returnType, interfaceTypes, ice);
|
|
|
|
if (moduleScope->varargPack)
|
|
|
|
normalize(*moduleScope->varargPack, interfaceTypes, ice);
|
|
|
|
}
|
2021-10-29 21:25:12 +01:00
|
|
|
|
2021-12-10 22:05:05 +00:00
|
|
|
for (auto& [name, tf] : moduleScope->exportedTypeBindings)
|
2022-04-15 00:57:43 +01:00
|
|
|
{
|
|
|
|
tf = clone(tf, interfaceTypes, cloneState);
|
|
|
|
if (FFlag::LuauLowerBoundsCalculation)
|
|
|
|
normalize(tf.type, interfaceTypes, ice);
|
|
|
|
}
|
2021-10-29 21:25:12 +01:00
|
|
|
|
|
|
|
for (TypeId ty : moduleScope->returnType)
|
2022-04-15 00:57:43 +01:00
|
|
|
{
|
2021-10-29 21:25:12 +01:00
|
|
|
if (get<GenericTypeVar>(follow(ty)))
|
2022-04-15 00:57:43 +01:00
|
|
|
{
|
|
|
|
auto t = asMutable(ty);
|
|
|
|
t->ty = AnyTypeVar{};
|
|
|
|
t->normal = true;
|
|
|
|
}
|
|
|
|
}
|
2021-10-29 21:25:12 +01:00
|
|
|
|
2022-04-21 22:44:27 +01:00
|
|
|
for (auto& [name, ty] : declaredGlobals)
|
2022-03-18 00:46:04 +00:00
|
|
|
{
|
2022-04-21 22:44:27 +01:00
|
|
|
ty = clone(ty, interfaceTypes, cloneState);
|
|
|
|
if (FFlag::LuauLowerBoundsCalculation)
|
|
|
|
normalize(ty, interfaceTypes, ice);
|
2022-03-18 00:46:04 +00:00
|
|
|
}
|
|
|
|
|
2021-10-29 21:25:12 +01:00
|
|
|
freeze(internalTypes);
|
|
|
|
freeze(interfaceTypes);
|
|
|
|
|
2022-04-21 22:44:27 +01:00
|
|
|
if (FFlag::LuauLosslessClone)
|
|
|
|
return false; // TODO: make function return void.
|
|
|
|
else
|
|
|
|
return cloneState.encounteredFreeType;
|
2021-10-29 21:25:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Luau
|