Skip to content

Commit

Permalink
Sync to upstream/release/602 (#1089)
Browse files Browse the repository at this point in the history
# What's changed?

* Fixed a bug in type cloning by maintaining persistent types.
* We now parse imprecise integer literals to report the imprecision as a
warning to developers.
* Add a compiler flag to specify the name of the statistics output file.

### New type solver

* Renamed `ConstraintGraphBuilder` to `ConstraintGenerator`
* LValues now take into account the type being assigned during
constraint generation.
* Normalization performance has been improved by 33% by replacing the an
internal usage of `std::unordered_set` with `DenseHashMap`.
* Normalization now has a helper to identify types that are equivalent
to `unknown`, which is being used to fix some bugs in subtyping.
* Uses of the old unifier in the new type solver have been eliminated.
* Improved error explanations for subtyping errors in `TypeChecker2`.

### Native code generation

* Expanded some of the statistics recorded during compilation to include
the number of instructions and blocks.
* Introduce instruction and block count limiters for controlling what
bytecode is translated into native code.
* Implement code generation for byteswap instruction.

### Internal Contributors

Co-authored-by: Aaron Weiss <[email protected]>
Co-authored-by: Alexander McCord <[email protected]>
Co-authored-by: Andy Friesen <[email protected]>
Co-authored-by: Aviral Goel <[email protected]>
Co-authored-by: Lily Brown <[email protected]>
  • Loading branch information
6 people authored Nov 3, 2023
1 parent 1a9159d commit 7105c81
Show file tree
Hide file tree
Showing 69 changed files with 1,015 additions and 581 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ struct InferencePack
}
};

struct ConstraintGraphBuilder
struct ConstraintGenerator
{
// A list of all the scopes in the module. This vector holds ownership of the
// scope pointers; the scopes themselves borrow pointers to other scopes to
Expand All @@ -68,7 +68,7 @@ struct ConstraintGraphBuilder
NotNull<BuiltinTypes> builtinTypes;
const NotNull<TypeArena> arena;
// The root scope of the module we're generating constraints for.
// This is null when the CGB is initially constructed.
// This is null when the CG is initially constructed.
Scope* rootScope;

struct InferredBinding
Expand Down Expand Up @@ -116,13 +116,13 @@ struct ConstraintGraphBuilder

DcrLogger* logger;

ConstraintGraphBuilder(ModulePtr module, NotNull<Normalizer> normalizer, NotNull<ModuleResolver> moduleResolver,
ConstraintGenerator(ModulePtr module, NotNull<Normalizer> normalizer, NotNull<ModuleResolver> moduleResolver,
NotNull<BuiltinTypes> builtinTypes, NotNull<InternalErrorReporter> ice, const ScopePtr& globalScope,
std::function<void(const ModuleName&, const ScopePtr&)> prepareModuleScope, DcrLogger* logger, NotNull<DataFlowGraph> dfg,
std::vector<RequireCycle> requireCycles);

/**
* The entry point to the ConstraintGraphBuilder. This will construct a set
* The entry point to the ConstraintGenerator. This will construct a set
* of scopes, constraints, and free types that can be solved later.
* @param block the root block to generate constraints for.
*/
Expand Down Expand Up @@ -232,12 +232,16 @@ struct ConstraintGraphBuilder
Inference check(const ScopePtr& scope, AstExprTable* expr, std::optional<TypeId> expectedType);
std::tuple<TypeId, TypeId, RefinementId> checkBinary(const ScopePtr& scope, AstExprBinary* binary, std::optional<TypeId> expectedType);

std::optional<TypeId> checkLValue(const ScopePtr& scope, AstExpr* expr);
std::optional<TypeId> checkLValue(const ScopePtr& scope, AstExprLocal* local);
std::optional<TypeId> checkLValue(const ScopePtr& scope, AstExprGlobal* global);
std::optional<TypeId> checkLValue(const ScopePtr& scope, AstExprIndexName* indexName);
std::optional<TypeId> checkLValue(const ScopePtr& scope, AstExprIndexExpr* indexExpr);
TypeId updateProperty(const ScopePtr& scope, AstExpr* expr);
/**
* Generate constraints to assign assignedTy to the expression expr
* @returns the type of the expression. This may or may not be assignedTy itself.
*/
std::optional<TypeId> checkLValue(const ScopePtr& scope, AstExpr* expr, TypeId assignedTy);
std::optional<TypeId> checkLValue(const ScopePtr& scope, AstExprLocal* local, TypeId assignedTy);
std::optional<TypeId> checkLValue(const ScopePtr& scope, AstExprGlobal* global, TypeId assignedTy);
std::optional<TypeId> checkLValue(const ScopePtr& scope, AstExprIndexName* indexName, TypeId assignedTy);
std::optional<TypeId> checkLValue(const ScopePtr& scope, AstExprIndexExpr* indexExpr, TypeId assignedTy);
TypeId updateProperty(const ScopePtr& scope, AstExpr* expr, TypeId assignedTy);

void updateLValueType(AstExpr* lvalue, TypeId ty);

Expand Down Expand Up @@ -324,7 +328,7 @@ struct ConstraintGraphBuilder

/** Scan the program for global definitions.
*
* ConstraintGraphBuilder needs to differentiate between globals and accesses to undefined symbols. Doing this "for
* ConstraintGenerator needs to differentiate between globals and accesses to undefined symbols. Doing this "for
* real" in a general way is going to be pretty hard, so we are choosing not to tackle that yet. For now, we do an
* initial scan of the AST and note what globals are defined.
*/
Expand Down
4 changes: 2 additions & 2 deletions Analysis/include/Luau/DataFlowGraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ struct DataFlowGraph
DataFlowGraph& operator=(DataFlowGraph&&) = default;

DefId getDef(const AstExpr* expr) const;
// Look up for the rvalue breadcrumb for a compound assignment.
// Look up for the rvalue def for a compound assignment.
std::optional<DefId> getRValueDefForCompoundAssign(const AstExpr* expr) const;

DefId getDef(const AstLocal* local) const;
Expand Down Expand Up @@ -64,7 +64,7 @@ struct DataFlowGraph

// Compound assignments are in a weird situation where the local being assigned to is also being used at its
// previous type implicitly in an rvalue position. This map provides the previous binding.
DenseHashMap<const AstExpr*, const Def*> compoundAssignBreadcrumbs{nullptr};
DenseHashMap<const AstExpr*, const Def*> compoundAssignDefs{nullptr};

DenseHashMap<const AstExpr*, const RefinementKey*> astRefinementKeys{nullptr};

Expand Down
3 changes: 2 additions & 1 deletion Analysis/include/Luau/Normalize.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ bool isConsistentSubtype(TypePackId subTy, TypePackId superTy, NotNull<Scope> sc
class TypeIds
{
private:
std::unordered_set<TypeId> types;
DenseHashMap<TypeId, bool> types{nullptr};
std::vector<TypeId> order;
std::size_t hash = 0;

Expand Down Expand Up @@ -277,6 +277,7 @@ struct NormalizedType
NormalizedType& operator=(NormalizedType&&) = default;

// IsType functions
bool isUnknown() const;
/// Returns true if the type is exactly a number. Behaves like Type::isNumber()
bool isExactlyNumber() const;

Expand Down
4 changes: 2 additions & 2 deletions Analysis/include/Luau/TypeChecker2.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

#pragma once

#include "Luau/Ast.h"
#include "Luau/Module.h"
#include "Luau/NotNull.h"

namespace Luau
Expand All @@ -13,6 +11,8 @@ struct BuiltinTypes;
struct DcrLogger;
struct TypeCheckLimits;
struct UnifierSharedState;
struct SourceModule;
struct Module;

void check(NotNull<BuiltinTypes> builtinTypes, NotNull<UnifierSharedState> sharedState, NotNull<TypeCheckLimits> limits, DcrLogger* logger,
const SourceModule& sourceModule, Module* module);
Expand Down
44 changes: 20 additions & 24 deletions Analysis/include/Luau/TypeOrPack.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,28 @@ namespace Luau

const void* ptr(TypeOrPack ty);

template<typename T>
const T* get(TypeOrPack ty)
template<typename T, typename std::enable_if_t<TypeOrPack::is_part_of_v<T>, bool> = true>
const T* get(const TypeOrPack& tyOrTp)
{
if constexpr (std::is_same_v<T, TypeId>)
return ty.get_if<TypeId>();
else if constexpr (std::is_same_v<T, TypePackId>)
return ty.get_if<TypePackId>();
else if constexpr (TypeVariant::is_part_of_v<T>)
{
if (auto innerTy = ty.get_if<TypeId>())
return get<T>(*innerTy);
else
return nullptr;
}
else if constexpr (TypePackVariant::is_part_of_v<T>)
{
if (auto innerTp = ty.get_if<TypePackId>())
return get<T>(*innerTp);
else
return nullptr;
}
return tyOrTp.get_if<T>();
}

template<typename T, typename std::enable_if_t<TypeVariant::is_part_of_v<T>, bool> = true>
const T* get(const TypeOrPack& tyOrTp)
{
if (const TypeId* ty = get<TypeId>(tyOrTp))
return get<T>(*ty);
else
return nullptr;
}

template<typename T, typename std::enable_if_t<TypePackVariant::is_part_of_v<T>, bool> = true>
const T* get(const TypeOrPack& tyOrTp)
{
if (const TypePackId* tp = get<TypePackId>(tyOrTp))
return get<T>(*tp);
else
{
static_assert(always_false_v<T>, "invalid T to get from TypeOrPack");
LUAU_UNREACHABLE();
}
return nullptr;
}

TypeOrPack follow(TypeOrPack ty);
Expand Down
23 changes: 18 additions & 5 deletions Analysis/src/Autocomplete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
#include "Luau/BuiltinDefinitions.h"
#include "Luau/Frontend.h"
#include "Luau/ToString.h"
#include "Luau/Subtyping.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypePack.h"

#include <algorithm>
#include <unordered_set>
#include <utility>

LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution);
LUAU_FASTFLAG(DebugLuauReadWriteProperties);
LUAU_FASTFLAG(LuauClipExtraHasEndProps);
LUAU_FASTFLAGVARIABLE(LuauAutocompleteDoEnd, false);
Expand Down Expand Up @@ -143,13 +145,24 @@ static bool checkTypeMatch(TypeId subTy, TypeId superTy, NotNull<Scope> scope, T
InternalErrorReporter iceReporter;
UnifierSharedState unifierState(&iceReporter);
Normalizer normalizer{typeArena, builtinTypes, NotNull{&unifierState}};
Unifier unifier(NotNull<Normalizer>{&normalizer}, scope, Location(), Variance::Covariant);

// Cost of normalization can be too high for autocomplete response time requirements
unifier.normalize = false;
unifier.checkInhabited = false;
if (FFlag::DebugLuauDeferredConstraintResolution)
{
Subtyping subtyping{builtinTypes, NotNull{typeArena}, NotNull{&normalizer}, NotNull{&iceReporter}, scope};

return subtyping.isSubtype(subTy, superTy).isSubtype;
}
else
{
Unifier unifier(NotNull<Normalizer>{&normalizer}, scope, Location(), Variance::Covariant);

// Cost of normalization can be too high for autocomplete response time requirements
unifier.normalize = false;
unifier.checkInhabited = false;

return unifier.canUnify(subTy, superTy).empty();
}

return unifier.canUnify(subTy, superTy).empty();
}

static TypeCorrectKind checkTypeCorrectKind(
Expand Down
2 changes: 1 addition & 1 deletion Analysis/src/BuiltinDefinitions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#include "Luau/Common.h"
#include "Luau/ToString.h"
#include "Luau/ConstraintSolver.h"
#include "Luau/ConstraintGraphBuilder.h"
#include "Luau/ConstraintGenerator.h"
#include "Luau/NotNull.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeFamily.h"
Expand Down
12 changes: 8 additions & 4 deletions Analysis/src/Clone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution)
LUAU_FASTINTVARIABLE(LuauTypeCloneRecursionLimit, 300)
LUAU_FASTFLAGVARIABLE(LuauCloneCyclicUnions, false)

LUAU_FASTFLAGVARIABLE(LuauStacklessTypeClone2, false)
LUAU_FASTFLAGVARIABLE(LuauStacklessTypeClone3, false)
LUAU_FASTINTVARIABLE(LuauTypeCloneIterationLimit, 100'000)

namespace Luau
Expand Down Expand Up @@ -118,6 +118,8 @@ class TypeCloner2
ty = follow(ty, FollowOption::DisableLazyTypeThunks);
if (auto it = types->find(ty); it != types->end())
return it->second;
else if (ty->persistent)
return ty;
return std::nullopt;
}

Expand All @@ -126,6 +128,8 @@ class TypeCloner2
tp = follow(tp);
if (auto it = packs->find(tp); it != packs->end())
return it->second;
else if (tp->persistent)
return tp;
return std::nullopt;
}

Expand Down Expand Up @@ -879,7 +883,7 @@ TypePackId clone(TypePackId tp, TypeArena& dest, CloneState& cloneState)
if (tp->persistent)
return tp;

if (FFlag::LuauStacklessTypeClone2)
if (FFlag::LuauStacklessTypeClone3)
{
TypeCloner2 cloner{NotNull{&dest}, cloneState.builtinTypes, NotNull{&cloneState.seenTypes}, NotNull{&cloneState.seenTypePacks}};
return cloner.clone(tp);
Expand All @@ -905,7 +909,7 @@ TypeId clone(TypeId typeId, TypeArena& dest, CloneState& cloneState)
if (typeId->persistent)
return typeId;

if (FFlag::LuauStacklessTypeClone2)
if (FFlag::LuauStacklessTypeClone3)
{
TypeCloner2 cloner{NotNull{&dest}, cloneState.builtinTypes, NotNull{&cloneState.seenTypes}, NotNull{&cloneState.seenTypePacks}};
return cloner.clone(typeId);
Expand Down Expand Up @@ -934,7 +938,7 @@ TypeId clone(TypeId typeId, TypeArena& dest, CloneState& cloneState)

TypeFun clone(const TypeFun& typeFun, TypeArena& dest, CloneState& cloneState)
{
if (FFlag::LuauStacklessTypeClone2)
if (FFlag::LuauStacklessTypeClone3)
{
TypeCloner2 cloner{NotNull{&dest}, cloneState.builtinTypes, NotNull{&cloneState.seenTypes}, NotNull{&cloneState.seenTypePacks}};

Expand Down
Loading

0 comments on commit 7105c81

Please sign in to comment.