Skip to content

Commit

Permalink
Sync to upstream/release/502
Browse files Browse the repository at this point in the history
Changes:
- Support for time tracing for analysis/compiler (not currently exposed
  through CLI)
- Support for type pack arguments in type aliases (#83)
- Basic support for require(path) in luau-analyze
- Add a lint warning for table.move with 0 index as part of
  TableOperation lint
- Remove last STL dependency from Luau.VM
- Minor VS2022 performance tuning

Co-authored-by: Rodactor <rodactor@roblox.com>
  • Loading branch information
zeux and rkaev-convex committed Nov 5, 2021
1 parent 4611052 commit 08c66ef
Show file tree
Hide file tree
Showing 70 changed files with 4,475 additions and 2,952 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
^build/
^coverage/
^fuzz/luau.pb.*
^crash-*
^default.prof*
^fuzz-*
^luau$
3 changes: 2 additions & 1 deletion Analysis/include/Luau/BuiltinDefinitions.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once

#include "TypeInfer.h"
#include "Luau/Scope.h"
#include "Luau/TypeInfer.h"

namespace Luau
{
Expand Down
1 change: 1 addition & 0 deletions Analysis/include/Luau/Error.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ struct IncorrectGenericParameterCount
Name name;
TypeFun typeFun;
size_t actualParameters;
size_t actualPackParameters;

bool operator==(const IncorrectGenericParameterCount& rhs) const;
};
Expand Down
58 changes: 21 additions & 37 deletions Analysis/include/Luau/FileResolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,51 +25,39 @@ struct SourceCode
Type type;
};

struct ModuleInfo
{
ModuleName name;
bool optional = false;
};

struct FileResolver
{
virtual ~FileResolver() {}

/** Fetch the source code associated with the provided ModuleName.
*
* FIXME: This requires a string copy!
*
* @returns The actual Lua code on success.
* @returns std::nullopt if no such file exists. When this occurs, type inference will report an UnknownRequire error.
*/
virtual std::optional<SourceCode> readSource(const ModuleName& name) = 0;

/** Does the module exist?
*
* Saves a string copy over reading the source and throwing it away.
*/
virtual bool moduleExists(const ModuleName& name) const = 0;

virtual std::optional<ModuleName> fromAstFragment(AstExpr* expr) const = 0;

/** Given a valid module name and a string of arbitrary data, figure out the concatenation.
*/
virtual ModuleName concat(const ModuleName& lhs, std::string_view rhs) const = 0;

/** Goes "up" a level in the hierarchy that the ModuleName represents.
*
* For instances, this is analogous to someInstance.Parent; for paths, this is equivalent to removing the last
* element of the path. Other ModuleName representations may have other ways of doing this.
*
* @returns The parent ModuleName, if one exists.
* @returns std::nullopt if there is no parent for this module name.
*/
virtual std::optional<ModuleName> getParentModuleName(const ModuleName& name) const = 0;
virtual std::optional<ModuleInfo> resolveModule(const ModuleInfo* context, AstExpr* expr)
{
return std::nullopt;
}

virtual std::optional<std::string> getHumanReadableModuleName_(const ModuleName& name) const
virtual std::string getHumanReadableModuleName(const ModuleName& name) const
{
return name;
}

virtual std::optional<std::string> getEnvironmentForModule(const ModuleName& name) const = 0;
virtual std::optional<std::string> getEnvironmentForModule(const ModuleName& name) const
{
return std::nullopt;
}

/** LanguageService only:
* std::optional<ModuleName> fromInstance(Instance* inst)
*/
// DEPRECATED APIS
// These are going to be removed with LuauNewRequireTracer
virtual bool moduleExists(const ModuleName& name) const = 0;
virtual std::optional<ModuleName> fromAstFragment(AstExpr* expr) const = 0;
virtual ModuleName concat(const ModuleName& lhs, std::string_view rhs) const = 0;
virtual std::optional<ModuleName> getParentModuleName(const ModuleName& name) const = 0;
};

struct NullFileResolver : FileResolver
Expand All @@ -94,10 +82,6 @@ struct NullFileResolver : FileResolver
{
return std::nullopt;
}
std::optional<std::string> getEnvironmentForModule(const ModuleName& name) const override
{
return std::nullopt;
}
};

} // namespace Luau
10 changes: 6 additions & 4 deletions Analysis/include/Luau/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,12 @@ struct Module
TypeArena internalTypes;

std::vector<std::pair<Location, ScopePtr>> scopes; // never empty
std::unordered_map<const AstExpr*, TypeId> astTypes;
std::unordered_map<const AstExpr*, TypeId> astExpectedTypes;
std::unordered_map<const AstExpr*, TypeId> astOriginalCallTypes;
std::unordered_map<const AstExpr*, TypeId> astOverloadResolvedTypes;

DenseHashMap<const AstExpr*, TypeId> astTypes{nullptr};
DenseHashMap<const AstExpr*, TypeId> astExpectedTypes{nullptr};
DenseHashMap<const AstExpr*, TypeId> astOriginalCallTypes{nullptr};
DenseHashMap<const AstExpr*, TypeId> astOverloadResolvedTypes{nullptr};

std::unordered_map<Name, TypeId> declaredGlobals;
ErrorVec errors;
Mode mode;
Expand Down
6 changes: 0 additions & 6 deletions Analysis/include/Luau/ModuleResolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,6 @@ struct Module;

using ModulePtr = std::shared_ptr<Module>;

struct ModuleInfo
{
ModuleName name;
bool optional = false;
};

struct ModuleResolver
{
virtual ~ModuleResolver() {}
Expand Down
5 changes: 2 additions & 3 deletions Analysis/include/Luau/RequireTracer.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,11 @@ struct AstLocal;

struct RequireTraceResult
{
DenseHashMap<const AstExpr*, ModuleName> exprs{0};
DenseHashMap<const AstExpr*, bool> optional{0};
DenseHashMap<const AstExpr*, ModuleInfo> exprs{nullptr};

std::vector<std::pair<ModuleName, Location>> requires;
};

RequireTraceResult traceRequires(FileResolver* fileResolver, AstStatBlock* root, ModuleName currentModuleName);
RequireTraceResult traceRequires(FileResolver* fileResolver, AstStatBlock* root, const ModuleName& currentModuleName);

} // namespace Luau
67 changes: 67 additions & 0 deletions Analysis/include/Luau/Scope.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once

#include "Luau/Location.h"
#include "Luau/TypeVar.h"

#include <unordered_map>
#include <optional>
#include <memory>

namespace Luau
{

struct Scope;

using ScopePtr = std::shared_ptr<Scope>;

struct Binding
{
TypeId typeId;
Location location;
bool deprecated = false;
std::string deprecatedSuggestion;
std::optional<std::string> documentationSymbol;
};

struct Scope
{
explicit Scope(TypePackId returnType); // root scope
explicit Scope(const ScopePtr& parent, int subLevel = 0); // child scope. Parent must not be nullptr.

const ScopePtr parent; // null for the root
std::unordered_map<Symbol, Binding> bindings;
TypePackId returnType;
bool breakOk = false;
std::optional<TypePackId> varargPack;

TypeLevel level;

std::unordered_map<Name, TypeFun> exportedTypeBindings;
std::unordered_map<Name, TypeFun> privateTypeBindings;
std::unordered_map<Name, Location> typeAliasLocations;

std::unordered_map<Name, std::unordered_map<Name, TypeFun>> importedTypeBindings;

std::optional<TypeId> lookup(const Symbol& name);

std::optional<TypeFun> lookupType(const Name& name);
std::optional<TypeFun> lookupImportedType(const Name& moduleAlias, const Name& name);

std::unordered_map<Name, TypePackId> privateTypePackBindings;
std::optional<TypePackId> lookupPack(const Name& name);

// WARNING: This function linearly scans for a string key of equal value! It is thus O(n**2)
std::optional<Binding> linearSearchForBinding(const std::string& name, bool traverseScopeChain = true);

RefinementMap refinements;

// For mutually recursive type aliases, it's important that
// they use the same types for the same names.
// For instance, in `type Tree<T> { data: T, children: Forest<T> } type Forest<T> = {Tree<T>}`
// we need that the generic type `T` in both cases is the same, so we use a cache.
std::unordered_map<Name, TypeId> typeAliasTypeParameters;
std::unordered_map<Name, TypePackId> typeAliasTypePackParameters;
};

} // namespace Luau
14 changes: 2 additions & 12 deletions Analysis/include/Luau/Substitution.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@
// `T`, and the type of `f` are in the same SCC, which is why `f` gets
// replaced.

LUAU_FASTFLAG(DebugLuauTrackOwningArena)

namespace Luau
{

Expand Down Expand Up @@ -188,20 +186,12 @@ struct Substitution : FindDirty
template<typename T>
TypeId addType(const T& tv)
{
TypeId allocated = currentModule->internalTypes.typeVars.allocate(tv);
if (FFlag::DebugLuauTrackOwningArena)
asMutable(allocated)->owningArena = &currentModule->internalTypes;

return allocated;
return currentModule->internalTypes.addType(tv);
}
template<typename T>
TypePackId addTypePack(const T& tp)
{
TypePackId allocated = currentModule->internalTypes.typePacks.allocate(tp);
if (FFlag::DebugLuauTrackOwningArena)
asMutable(allocated)->owningArena = &currentModule->internalTypes;

return allocated;
return currentModule->internalTypes.addTypePack(TypePackVar{tp});
}
};

Expand Down
56 changes: 6 additions & 50 deletions Analysis/include/Luau/TypeInfer.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,10 @@ struct ApplyTypeFunction : Substitution
{
TypeLevel level;
bool encounteredForwardedType;
std::unordered_map<TypeId, TypeId> arguments;
std::unordered_map<TypeId, TypeId> typeArguments;
std::unordered_map<TypePackId, TypePackId> typePackArguments;
bool ignoreChildren(TypeId ty) override;
bool ignoreChildren(TypePackId tp) override;
bool isDirty(TypeId ty) override;
bool isDirty(TypePackId tp) override;
TypeId clean(TypeId ty) override;
Expand Down Expand Up @@ -328,7 +331,8 @@ struct TypeChecker
TypeId resolveType(const ScopePtr& scope, const AstType& annotation, bool canBeGeneric = false);
TypePackId resolveTypePack(const ScopePtr& scope, const AstTypeList& types);
TypePackId resolveTypePack(const ScopePtr& scope, const AstTypePack& annotation);
TypeId instantiateTypeFun(const ScopePtr& scope, const TypeFun& tf, const std::vector<TypeId>& typeParams, const Location& location);
TypeId instantiateTypeFun(const ScopePtr& scope, const TypeFun& tf, const std::vector<TypeId>& typeParams,
const std::vector<TypePackId>& typePackParams, const Location& location);

// Note: `scope` must be a fresh scope.
std::pair<std::vector<TypeId>, std::vector<TypePackId>> createGenericTypes(
Expand Down Expand Up @@ -398,54 +402,6 @@ struct TypeChecker
int recursionCount = 0;
};

struct Binding
{
TypeId typeId;
Location location;
bool deprecated = false;
std::string deprecatedSuggestion;
std::optional<std::string> documentationSymbol;
};

struct Scope
{
explicit Scope(TypePackId returnType); // root scope
explicit Scope(const ScopePtr& parent, int subLevel = 0); // child scope. Parent must not be nullptr.

const ScopePtr parent; // null for the root
std::unordered_map<Symbol, Binding> bindings;
TypePackId returnType;
bool breakOk = false;
std::optional<TypePackId> varargPack;

TypeLevel level;

std::unordered_map<Name, TypeFun> exportedTypeBindings;
std::unordered_map<Name, TypeFun> privateTypeBindings;
std::unordered_map<Name, Location> typeAliasLocations;

std::unordered_map<Name, std::unordered_map<Name, TypeFun>> importedTypeBindings;

std::optional<TypeId> lookup(const Symbol& name);

std::optional<TypeFun> lookupType(const Name& name);
std::optional<TypeFun> lookupImportedType(const Name& moduleAlias, const Name& name);

std::unordered_map<Name, TypePackId> privateTypePackBindings;
std::optional<TypePackId> lookupPack(const Name& name);

// WARNING: This function linearly scans for a string key of equal value! It is thus O(n**2)
std::optional<Binding> linearSearchForBinding(const std::string& name, bool traverseScopeChain = true);

RefinementMap refinements;

// For mutually recursive type aliases, it's important that
// they use the same types for the same names.
// For instance, in `type Tree<T> { data: T, children: Forest<T> } type Forest<T> = {Tree<T>}`
// we need that the generic type `T` in both cases is the same, so we use a cache.
std::unordered_map<Name, TypeId> typeAliasParameters;
};

// Unit test hook
void setPrintLine(void (*pl)(const std::string& s));
void resetPrintLine();
Expand Down
3 changes: 2 additions & 1 deletion Analysis/include/Luau/TypePack.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ bool areEqual(SeenSet& seen, const TypePackVar& lhs, const TypePackVar& rhs);

TypePackId follow(TypePackId tp);

size_t size(const TypePackId tp);
size_t size(TypePackId tp);
bool finite(TypePackId tp);
size_t size(const TypePack& tp);
std::optional<TypeId> first(TypePackId tp);

Expand Down
22 changes: 17 additions & 5 deletions Analysis/include/Luau/TypeVar.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ struct TableTypeVar

std::map<Name, Location> methodDefinitionLocations;
std::vector<TypeId> instantiatedTypeParams;
std::vector<TypePackId> instantiatedTypePackParams;
ModuleName definitionModuleName;

std::optional<TypeId> boundTo;
Expand Down Expand Up @@ -284,15 +285,30 @@ struct ClassTypeVar

struct TypeFun
{
/// These should all be generic
// These should all be generic
std::vector<TypeId> typeParams;
std::vector<TypePackId> typePackParams;

/** The underlying type.
*
* WARNING! This is not safe to use as a type if typeParams is not empty!!
* You must first use TypeChecker::instantiateTypeFun to turn it into a real type.
*/
TypeId type;

TypeFun() = default;
TypeFun(std::vector<TypeId> typeParams, TypeId type)
: typeParams(std::move(typeParams))
, type(type)
{
}

TypeFun(std::vector<TypeId> typeParams, std::vector<TypePackId> typePackParams, TypeId type)
: typeParams(std::move(typeParams))
, typePackParams(std::move(typePackParams))
, type(type)
{
}
};

// Anything! All static checking is off.
Expand Down Expand Up @@ -524,8 +540,4 @@ UnionTypeVarIterator end(const UnionTypeVar* utv);
using TypeIdPredicate = std::function<std::optional<TypeId>(TypeId)>;
std::vector<TypeId> filterMap(TypeId type, TypeIdPredicate predicate);

// TEMP: Clip this prototype with FFlag::LuauStringMetatable
std::optional<ExprResult<TypePackId>> magicFunctionFormat(
struct TypeChecker& typechecker, const std::shared_ptr<struct Scope>& scope, const AstExprCall& expr, ExprResult<TypePackId> exprResult);

} // namespace Luau
Loading

0 comments on commit 08c66ef

Please sign in to comment.