Skip to content

Commit

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

* Compiler now targets bytecode version 5 by default, this includes
support for vector type literals and sub/div opcodes with a constant on
lhs

### New Type Solver

* Normalizer type inhabitance check has been optimized
* Added ability to reduce cyclic `and`/`or` type families 

### Native Code Generation

* `CodeGen::compile` now returns more specific causes of a code
generation failure
* Fixed linking issues on platforms that don't support unwind frame data
registration

---

### Internal Contributors

Co-authored-by: Andy Friesen <[email protected]>
Co-authored-by: Aviral Goel <[email protected]>
Co-authored-by: Vyacheslav Egorov <[email protected]>

---------

Co-authored-by: Aaron Weiss <[email protected]>
Co-authored-by: Alexander McCord <[email protected]>
Co-authored-by: Andy Friesen <[email protected]>
Co-authored-by: Vighnesh <[email protected]>
Co-authored-by: Aviral Goel <[email protected]>
Co-authored-by: David Cope <[email protected]>
Co-authored-by: Lily Brown <[email protected]>
  • Loading branch information
8 people authored Feb 16, 2024
1 parent d6c2472 commit ea14e65
Show file tree
Hide file tree
Showing 91 changed files with 1,060 additions and 946 deletions.
4 changes: 2 additions & 2 deletions Analysis/include/Luau/Constraint.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,8 +255,8 @@ struct ReducePackConstraint
};

using ConstraintV = Variant<SubtypeConstraint, PackSubtypeConstraint, GeneralizationConstraint, InstantiationConstraint, IterableConstraint,
NameConstraint, TypeAliasExpansionConstraint, FunctionCallConstraint, FunctionCheckConstraint, PrimitiveTypeConstraint, HasPropConstraint, SetPropConstraint,
SetIndexerConstraint, SingletonOrTopTypeConstraint, UnpackConstraint, SetOpConstraint, ReduceConstraint, ReducePackConstraint>;
NameConstraint, TypeAliasExpansionConstraint, FunctionCallConstraint, FunctionCheckConstraint, PrimitiveTypeConstraint, HasPropConstraint,
SetPropConstraint, SetIndexerConstraint, SingletonOrTopTypeConstraint, UnpackConstraint, SetOpConstraint, ReduceConstraint, ReducePackConstraint>;

struct Constraint
{
Expand Down
13 changes: 7 additions & 6 deletions Analysis/include/Luau/ConstraintGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,9 @@ struct ConstraintGenerator

DcrLogger* logger;

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);
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 ConstraintGenerator. This will construct a set
Expand Down Expand Up @@ -190,8 +189,10 @@ struct ConstraintGenerator
};

using RefinementContext = InsertionOrderedMap<DefId, RefinementPartition>;
void unionRefinements(const ScopePtr& scope, Location location, const RefinementContext& lhs, const RefinementContext& rhs, RefinementContext& dest, std::vector<ConstraintV>* constraints);
void computeRefinement(const ScopePtr& scope, Location location, RefinementId refinement, RefinementContext* refis, bool sense, bool eq, std::vector<ConstraintV>* constraints);
void unionRefinements(const ScopePtr& scope, Location location, const RefinementContext& lhs, const RefinementContext& rhs,
RefinementContext& dest, std::vector<ConstraintV>* constraints);
void computeRefinement(const ScopePtr& scope, Location location, RefinementId refinement, RefinementContext* refis, bool sense, bool eq,
std::vector<ConstraintV>* constraints);
void applyRefinements(const ScopePtr& scope, Location location, RefinementId refinement);

ControlFlow visitBlockWithoutChildScope(const ScopePtr& scope, AstStatBlock* block);
Expand Down
5 changes: 3 additions & 2 deletions Analysis/include/Luau/Normalize.h
Original file line number Diff line number Diff line change
Expand Up @@ -393,8 +393,9 @@ class Normalizer

// Check for inhabitance
bool isInhabited(TypeId ty);
bool isInhabited(TypeId ty, Set<TypeId> seen);
bool isInhabited(const NormalizedType* norm, Set<TypeId> seen = {nullptr});
bool isInhabited(TypeId ty, Set<TypeId>& seen);
bool isInhabited(const NormalizedType* norm);
bool isInhabited(const NormalizedType* norm, Set<TypeId>& seen);

// Check for intersections being inhabited
bool isIntersectionInhabited(TypeId left, TypeId right);
Expand Down
4 changes: 3 additions & 1 deletion Analysis/include/Luau/Set.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ class Set
const_iterator(typename Impl::const_iterator impl, typename Impl::const_iterator end)
: impl(impl)
, end(end)
{}
{
}

const T& operator*() const
{
Expand Down Expand Up @@ -168,6 +169,7 @@ class Set
++*this;
return res;
}

private:
typename Impl::const_iterator impl;
typename Impl::const_iterator end;
Expand Down
27 changes: 16 additions & 11 deletions Analysis/include/Luau/Subtyping.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ struct SubtypingResult
bool isSubtype = false;
bool normalizationTooComplex = false;
bool isCacheable = true;

ErrorVec errors;
/// The reason for isSubtype to be false. May not be present even if
/// isSubtype is false, depending on the input types.
SubtypingReasonings reasoning{kEmptyReasoning};
Expand All @@ -78,6 +78,7 @@ struct SubtypingResult
SubtypingResult& withBothPath(TypePath::Path path);
SubtypingResult& withSubPath(TypePath::Path path);
SubtypingResult& withSuperPath(TypePath::Path path);
SubtypingResult& withErrors(ErrorVec& err);

// Only negates the `isSubtype`.
static SubtypingResult negate(const SubtypingResult& result);
Expand Down Expand Up @@ -211,18 +212,22 @@ struct Subtyping
template<typename T, typename Container>
TypeId makeAggregateType(const Container& container, TypeId orElse);

template<typename T>
T handleTypeFamilyReductionResult(const TypeFamilyInstanceType* tf)

std::pair<TypeId, ErrorVec> handleTypeFamilyReductionResult(const TypeFamilyInstanceType* familyInstance)
{
TypeFamilyContext context{arena, builtinTypes, scope, normalizer, iceReporter, NotNull{&limits}};
TypeFamilyReductionResult<TypeId> result = tf->family->reducer(tf->typeArguments, tf->packArguments, NotNull{&context});
if (!result.blockedTypes.empty())
unexpected(result.blockedTypes[0]);
else if (!result.blockedPacks.empty())
unexpected(result.blockedPacks[0]);
else if (result.uninhabited || result.result == std::nullopt)
return builtinTypes->neverType;
return *result.result;
TypeId family = arena->addType(*familyInstance);
std::string familyString = toString(family);
FamilyGraphReductionResult result = reduceFamilies(family, {}, context, true);
ErrorVec errors;
if (result.blockedTypes.size() != 0 || result.blockedPacks.size() != 0)
{
errors.push_back(TypeError{{}, UninhabitedTypeFamily{family}});
return {builtinTypes->neverType, errors};
}
if (result.reducedTypes.contains(family))
return {family, errors};
return {builtinTypes->neverType, errors};
}

[[noreturn]] void unexpected(TypeId ty);
Expand Down
9 changes: 5 additions & 4 deletions Analysis/include/Luau/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,8 @@ struct Property
// TODO: Kill all constructors in favor of `Property::rw(TypeId read, TypeId write)` and friends.
Property();
Property(TypeId readTy, bool deprecated = false, const std::string& deprecatedSuggestion = "", std::optional<Location> location = std::nullopt,
const Tags& tags = {}, const std::optional<std::string>& documentationSymbol = std::nullopt, std::optional<Location> typeLocation = std::nullopt);
const Tags& tags = {}, const std::optional<std::string>& documentationSymbol = std::nullopt,
std::optional<Location> typeLocation = std::nullopt);

// DEPRECATED: Should only be called in non-RWP! We assert that the `readTy` is not nullopt.
// TODO: Kill once we don't have non-RWP.
Expand Down Expand Up @@ -639,9 +640,9 @@ struct NegationType

using ErrorType = Unifiable::Error;

using TypeVariant =
Unifiable::Variant<TypeId, FreeType, LocalType, GenericType, PrimitiveType, BlockedType, PendingExpansionType, SingletonType, FunctionType, TableType,
MetatableType, ClassType, AnyType, UnionType, IntersectionType, LazyType, UnknownType, NeverType, NegationType, TypeFamilyInstanceType>;
using TypeVariant = Unifiable::Variant<TypeId, FreeType, LocalType, GenericType, PrimitiveType, BlockedType, PendingExpansionType, SingletonType,
FunctionType, TableType, MetatableType, ClassType, AnyType, UnionType, IntersectionType, LazyType, UnknownType, NeverType, NegationType,
TypeFamilyInstanceType>;

struct Type final
{
Expand Down
8 changes: 6 additions & 2 deletions Analysis/include/Luau/TypeFamily.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ struct TypeFamilyReductionResult
std::vector<TypePackId> blockedPacks;
};

template<typename T>
using ReducerFunction =
std::function<TypeFamilyReductionResult<T>(T, const std::vector<TypeId>&, const std::vector<TypePackId>&, NotNull<TypeFamilyContext>)>;

/// Represents a type function that may be applied to map a series of types and
/// type packs to a single output type.
struct TypeFamily
Expand All @@ -85,7 +89,7 @@ struct TypeFamily
std::string name;

/// The reducer function for the type family.
std::function<TypeFamilyReductionResult<TypeId>(const std::vector<TypeId>&, const std::vector<TypePackId>&, NotNull<TypeFamilyContext>)> reducer;
ReducerFunction<TypeId> reducer;
};

/// Represents a type function that may be applied to map a series of types and
Expand All @@ -97,7 +101,7 @@ struct TypePackFamily
std::string name;

/// The reducer function for the type pack family.
std::function<TypeFamilyReductionResult<TypePackId>(const std::vector<TypeId>&, const std::vector<TypePackId>&, NotNull<TypeFamilyContext>)> reducer;
ReducerFunction<TypePackId> reducer;
};

struct FamilyGraphReductionResult
Expand Down
4 changes: 1 addition & 3 deletions Analysis/include/Luau/TypePath.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,7 @@ struct Path
std::vector<Component> components;

/// Creates a new empty Path.
Path()
{
}
Path() {}

/// Creates a new Path from a list of components.
explicit Path(std::vector<Component> components)
Expand Down
11 changes: 9 additions & 2 deletions Analysis/include/Luau/TypeUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,15 @@ struct ErrorSuppression
};

ErrorSuppression() = default;
constexpr ErrorSuppression(Value enumValue) : value(enumValue) { }
constexpr ErrorSuppression(Value enumValue)
: value(enumValue)
{
}

constexpr operator Value() const { return value; }
constexpr operator Value() const
{
return value;
}
explicit operator bool() const = delete;

ErrorSuppression orElse(const ErrorSuppression& other) const
Expand All @@ -81,6 +87,7 @@ struct ErrorSuppression
return *this;
}
}

private:
Value value;
};
Expand Down
1 change: 0 additions & 1 deletion Analysis/src/Autocomplete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,6 @@ static bool checkTypeMatch(TypeId subTy, TypeId superTy, NotNull<Scope> scope, T

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

}

static TypeCorrectKind checkTypeCorrectKind(
Expand Down
79 changes: 32 additions & 47 deletions Analysis/src/ConstraintGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,7 @@ struct HasFreeType : TypeOnceVisitor
{
bool result = false;

HasFreeType()
{
}
HasFreeType() {}

bool visit(TypeId ty) override
{
Expand Down Expand Up @@ -288,7 +286,7 @@ std::optional<TypeId> ConstraintGenerator::lookup(const ScopePtr& scope, DefId d
// `scope->lookup(operand)` may return nothing because we only bind a type to that operand
// once we've seen that particular `DefId`. In this case, we need to prototype those types
// and use those at a later time.
std::optional<TypeId> ty = lookup(scope, operand, /*prototype*/false);
std::optional<TypeId> ty = lookup(scope, operand, /*prototype*/ false);
if (!ty)
{
ty = arena->addType(BlockedType{});
Expand All @@ -315,7 +313,8 @@ NotNull<Constraint> ConstraintGenerator::addConstraint(const ScopePtr& scope, st
return NotNull{constraints.emplace_back(std::move(c)).get()};
}

void ConstraintGenerator::unionRefinements(const ScopePtr& scope, Location location, const RefinementContext& lhs, const RefinementContext& rhs, RefinementContext& dest, std::vector<ConstraintV>* constraints)
void ConstraintGenerator::unionRefinements(const ScopePtr& scope, Location location, const RefinementContext& lhs, const RefinementContext& rhs,
RefinementContext& dest, std::vector<ConstraintV>* constraints)
{
const auto intersect = [&](const std::vector<TypeId>& types) {
if (1 == types.size())
Expand Down Expand Up @@ -346,7 +345,8 @@ void ConstraintGenerator::unionRefinements(const ScopePtr& scope, Location locat
}
}

void ConstraintGenerator::computeRefinement(const ScopePtr& scope, Location location, RefinementId refinement, RefinementContext* refis, bool sense, bool eq, std::vector<ConstraintV>* constraints)
void ConstraintGenerator::computeRefinement(const ScopePtr& scope, Location location, RefinementId refinement, RefinementContext* refis, bool sense,
bool eq, std::vector<ConstraintV>* constraints)
{
if (!refinement)
return;
Expand Down Expand Up @@ -907,19 +907,17 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatLocalFuncti
std::make_unique<Constraint>(constraintScope, function->name->location, GeneralizationConstraint{functionType, sig.signature});

Constraint* previous = nullptr;
forEachConstraint(start, end, this,
[&c, &previous](const ConstraintPtr& constraint)
{
c->dependencies.push_back(NotNull{constraint.get()});
forEachConstraint(start, end, this, [&c, &previous](const ConstraintPtr& constraint) {
c->dependencies.push_back(NotNull{constraint.get()});

if (auto psc = get<PackSubtypeConstraint>(*constraint); psc && psc->returns)
{
if (previous)
constraint->dependencies.push_back(NotNull{previous});
if (auto psc = get<PackSubtypeConstraint>(*constraint); psc && psc->returns)
{
if (previous)
constraint->dependencies.push_back(NotNull{previous});

previous = constraint.get();
}
});
previous = constraint.get();
}
});

addConstraint(scope, std::move(c));
module->astTypes[function->func] = functionType;
Expand Down Expand Up @@ -1018,20 +1016,18 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatFunction* f
std::make_unique<Constraint>(constraintScope, function->name->location, GeneralizationConstraint{generalizedType, sig.signature});

Constraint* previous = nullptr;
forEachConstraint(start, end, this,
[&c, &excludeList, &previous](const ConstraintPtr& constraint)
{
if (!excludeList.contains(constraint.get()))
c->dependencies.push_back(NotNull{constraint.get()});
forEachConstraint(start, end, this, [&c, &excludeList, &previous](const ConstraintPtr& constraint) {
if (!excludeList.contains(constraint.get()))
c->dependencies.push_back(NotNull{constraint.get()});

if (auto psc = get<PackSubtypeConstraint>(*constraint); psc && psc->returns)
{
if (previous)
constraint->dependencies.push_back(NotNull{previous});
if (auto psc = get<PackSubtypeConstraint>(*constraint); psc && psc->returns)
{
if (previous)
constraint->dependencies.push_back(NotNull{previous});

previous = constraint.get();
}
});
previous = constraint.get();
}
});

addConstraint(scope, std::move(c));
}
Expand Down Expand Up @@ -1470,8 +1466,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatError* erro
return ControlFlow::None;
}

InferencePack ConstraintGenerator::checkPack(
const ScopePtr& scope, AstArray<AstExpr*> exprs, const std::vector<std::optional<TypeId>>& expectedTypes)
InferencePack ConstraintGenerator::checkPack(const ScopePtr& scope, AstArray<AstExpr*> exprs, const std::vector<std::optional<TypeId>>& expectedTypes)
{
std::vector<TypeId> head;
std::optional<TypePackId> tail;
Expand Down Expand Up @@ -1708,14 +1703,8 @@ InferencePack ConstraintGenerator::checkPack(const ScopePtr& scope, AstExprCall*
* 4. Solve the call
*/

NotNull<Constraint> checkConstraint = addConstraint(scope, call->func->location,
FunctionCheckConstraint{
fnType,
argPack,
call,
NotNull{&module->astExpectedTypes}
}
);
NotNull<Constraint> checkConstraint =
addConstraint(scope, call->func->location, FunctionCheckConstraint{fnType, argPack, call, NotNull{&module->astExpectedTypes}});

forEachConstraint(funcBeginCheckpoint, funcEndCheckpoint, this, [checkConstraint](const ConstraintPtr& constraint) {
checkConstraint->dependencies.emplace_back(constraint.get());
Expand Down Expand Up @@ -1743,8 +1732,7 @@ InferencePack ConstraintGenerator::checkPack(const ScopePtr& scope, AstExprCall*
}
}

Inference ConstraintGenerator::check(
const ScopePtr& scope, AstExpr* expr, std::optional<TypeId> expectedType, bool forceSingleton, bool generalize)
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExpr* expr, std::optional<TypeId> expectedType, bool forceSingleton, bool generalize)
{
RecursionCounter counter{&recursionCount};

Expand Down Expand Up @@ -2403,11 +2391,9 @@ std::optional<TypeId> ConstraintGenerator::checkLValue(const ScopePtr& scope, As

if (transform)
{
addConstraint(scope, local->location, UnpackConstraint{
arena->addTypePack({*ty}),
arena->addTypePack({assignedTy}),
/*resultIsLValue*/ true
});
addConstraint(scope, local->location,
UnpackConstraint{arena->addTypePack({*ty}), arena->addTypePack({assignedTy}),
/*resultIsLValue*/ true});

recordInferredBinding(local->local, *ty);
}
Expand Down Expand Up @@ -3395,7 +3381,6 @@ void ConstraintGenerator::fillInInferredBindings(const ScopePtr& globalScope, As

scope->bindings[symbol] = Binding{ty, location};
}

}
}

Expand Down
3 changes: 2 additions & 1 deletion Analysis/src/ConstraintSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1184,7 +1184,8 @@ bool ConstraintSolver::tryDispatch(const FunctionCheckConstraint& c, NotNull<con
}
}
}
else if (expr->is<AstExprConstantBool>() || expr->is<AstExprConstantString>() || expr->is<AstExprConstantNumber>() || expr->is<AstExprConstantNil>() || expr->is<AstExprTable>())
else if (expr->is<AstExprConstantBool>() || expr->is<AstExprConstantString>() || expr->is<AstExprConstantNumber>() ||
expr->is<AstExprConstantNil>() || expr->is<AstExprTable>())
{
Unifier2 u2{arena, builtinTypes, constraint->scope, NotNull{&iceReporter}};
u2.unify(actualArgTy, expectedArgTy);
Expand Down
3 changes: 2 additions & 1 deletion Analysis/src/Frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1289,7 +1289,8 @@ ModulePtr Frontend::check(const SourceModule& sourceModule, Mode mode, std::vect
{
return Luau::check(sourceModule, mode, requireCycles, builtinTypes, NotNull{&iceHandler},
NotNull{forAutocomplete ? &moduleResolverForAutocomplete : &moduleResolver}, NotNull{fileResolver},
environmentScope ? *environmentScope : globals.globalScope, prepareModuleScopeWrap, options, typeCheckLimits, recordJsonLog, writeJsonLog);
environmentScope ? *environmentScope : globals.globalScope, prepareModuleScopeWrap, options, typeCheckLimits, recordJsonLog,
writeJsonLog);
}
catch (const InternalCompilerError& err)
{
Expand Down
Loading

0 comments on commit ea14e65

Please sign in to comment.