Skip to content

Commit

Permalink
Sync to upstream/release/559 (#804)
Browse files Browse the repository at this point in the history
* Fix autocompletion of if-then-else expressions
* Fix a potential crash surrounding improper use of `%*` in a string
format specifier
* All Python scripts now invoke Python via `python3` rather than
`python`.
* Improved error handling for string interpolation with too many
arguments.

Co-authored-by: Arseny Kapoulkine <[email protected]>
Co-authored-by: Vyacheslav Egorov <[email protected]>
  • Loading branch information
3 people authored Jan 13, 2023
1 parent 0af1041 commit a5c6a38
Show file tree
Hide file tree
Showing 54 changed files with 2,186 additions and 823 deletions.
25 changes: 15 additions & 10 deletions Analysis/include/Luau/Predicate.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,30 +57,35 @@ struct AndPredicate
PredicateVec lhs;
PredicateVec rhs;

AndPredicate(PredicateVec&& lhs, PredicateVec&& rhs)
: lhs(std::move(lhs))
, rhs(std::move(rhs))
{
}
AndPredicate(PredicateVec&& lhs, PredicateVec&& rhs);
};

struct OrPredicate
{
PredicateVec lhs;
PredicateVec rhs;

OrPredicate(PredicateVec&& lhs, PredicateVec&& rhs)
: lhs(std::move(lhs))
, rhs(std::move(rhs))
{
}
OrPredicate(PredicateVec&& lhs, PredicateVec&& rhs);
};

struct NotPredicate
{
PredicateVec predicates;
};

// Outside definition works around clang 15 issue where vector instantiation is triggered while Predicate is still incomplete
inline AndPredicate::AndPredicate(PredicateVec&& lhs, PredicateVec&& rhs)
: lhs(std::move(lhs))
, rhs(std::move(rhs))
{
}

inline OrPredicate::OrPredicate(PredicateVec&& lhs, PredicateVec&& rhs)
: lhs(std::move(lhs))
, rhs(std::move(rhs))
{
}

template<typename T>
const T* get(const Predicate& predicate)
{
Expand Down
1 change: 0 additions & 1 deletion Analysis/include/Luau/ToString.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ struct ToStringOptions
bool hideTableKind = false; // If true, all tables will be surrounded with plain '{}'
bool hideNamedFunctionTypeParameters = false; // If true, type parameters of functions will be hidden at top-level.
bool hideFunctionSelfArgument = false; // If true, `self: X` will be omitted from the function signature if the function has self
bool DEPRECATED_indent = false; // TODO Deprecated field, prune when clipping flag FFlagLuauLineBreaksDeterminIndents
size_t maxTableLength = size_t(FInt::LuauTableTypeMaximumStringifierLength); // Only applied to TableTypes
size_t maxTypeLength = size_t(FInt::LuauTypeMaximumStringifierLength);
ToStringNameMap nameMap;
Expand Down
4 changes: 2 additions & 2 deletions Analysis/include/Luau/TypeReduction.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ struct TypeReduction
DenseHashMap<TypeId, TypeId> cachedTypes{nullptr};
DenseHashMap<TypePackId, TypePackId> cachedTypePacks{nullptr};

std::optional<TypeId> reduceImpl(TypeId ty);
std::optional<TypePackId> reduceImpl(TypePackId tp);
std::pair<std::optional<TypeId>, bool> reduceImpl(TypeId ty);
std::pair<std::optional<TypePackId>, bool> reduceImpl(TypePackId tp);

// Computes an *estimated length* of the cartesian product of the given type.
size_t cartesianProductSize(TypeId ty) const;
Expand Down
19 changes: 17 additions & 2 deletions Analysis/src/Autocomplete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <utility>

LUAU_FASTFLAGVARIABLE(LuauCompleteTableKeysBetter, false);
LUAU_FASTFLAGVARIABLE(LuauFixAutocompleteInIf, false);

static const std::unordered_set<std::string> kStatementStartingKeywords = {
"while", "if", "local", "repeat", "function", "do", "for", "return", "break", "continue", "type", "export"};
Expand Down Expand Up @@ -1487,8 +1488,22 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
return {{{"then", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword};
}
else if (AstStatIf* statIf = extractStat<AstStatIf>(ancestry);
statIf && (!statIf->thenLocation || statIf->thenLocation->containsClosed(position)))
return {{{"then", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword};
statIf && (!statIf->thenLocation || statIf->thenLocation->containsClosed(position)) &&
(!FFlag::LuauFixAutocompleteInIf || (statIf->condition && !statIf->condition->location.containsClosed(position))))
{
if (FFlag::LuauFixAutocompleteInIf)
{
AutocompleteEntryMap ret;
ret["then"] = {AutocompleteEntryKind::Keyword};
ret["and"] = {AutocompleteEntryKind::Keyword};
ret["or"] = {AutocompleteEntryKind::Keyword};
return {std::move(ret), ancestry, AutocompleteContext::Keyword};
}
else
{
return {{{"then", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword};
}
}
else if (AstStatRepeat* statRepeat = node->as<AstStatRepeat>(); statRepeat && statRepeat->condition->is<AstExprError>())
return autocompleteExpression(sourceModule, *module, builtinTypes, typeArena, ancestry, position);
else if (AstStatRepeat* statRepeat = extractStat<AstStatRepeat>(ancestry); statRepeat)
Expand Down
25 changes: 5 additions & 20 deletions Analysis/src/ToString.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@

LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution)
LUAU_FASTFLAG(LuauUnknownAndNeverType)
LUAU_FASTFLAGVARIABLE(LuauLineBreaksDetermineIndents, false)
LUAU_FASTFLAGVARIABLE(LuauFunctionReturnStringificationFixup, false)
LUAU_FASTFLAGVARIABLE(LuauUnseeArrayTtv, false)
LUAU_FASTFLAGVARIABLE(LuauSerializeNilUnionAsNil, false)

/*
* Prefix generic typenames with gen-
Expand Down Expand Up @@ -277,20 +275,10 @@ struct StringifierState
private:
void emitIndentation()
{
if (!FFlag::LuauLineBreaksDetermineIndents)
{
if (!opts.DEPRECATED_indent)
return;

emit(std::string(indentation, ' '));
}
else
{
if (!opts.useLineBreaks)
return;
if (!opts.useLineBreaks)
return;

emit(std::string(indentation, ' '));
}
emit(std::string(indentation, ' '));
}
};

Expand Down Expand Up @@ -781,11 +769,8 @@ struct TypeStringifier
if (results.size() > 1)
s = ")?";

if (FFlag::LuauSerializeNilUnionAsNil)
{
if (!hasNonNilDisjunct)
s = "nil";
}
if (!hasNonNilDisjunct)
s = "nil";

state.emit(s);
}
Expand Down
92 changes: 66 additions & 26 deletions Analysis/src/TypeReduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ struct TypeReducer
NotNull<BuiltinTypes> builtinTypes;
NotNull<InternalErrorReporter> handle;

std::unordered_map<TypeId, TypeId> copies;
std::deque<const void*> seen;
int depth = 0;

// When we encounter _any type_ that which is usually mutated in-place, we need to not cache the result.
// e.g. `'a & {} T` may have an upper bound constraint `{}` placed upon `'a`, but this constraint was not
// known when we decided to reduce this intersection type. By not caching, we'll always be forced to perform
// the reduction calculus over again.
bool cacheOk = true;

TypeId reduce(TypeId ty);
TypePackId reduce(TypePackId tp);

Expand All @@ -60,13 +70,11 @@ struct TypeReducer
TypeId functionType(TypeId ty);
TypeId negationType(TypeId ty);

std::deque<const void*> seen;
int depth = 0;

RecursionGuard guard(TypeId ty);
RecursionGuard guard(TypePackId tp);

std::unordered_map<TypeId, TypeId> copies;
void checkCacheable(TypeId ty);
void checkCacheable(TypePackId tp);

template<typename T>
LUAU_NOINLINE std::pair<TypeId, T*> copy(TypeId ty, const T* t)
Expand Down Expand Up @@ -153,6 +161,7 @@ TypeId TypeReducer::reduce(TypeId ty)
return ty;

RecursionGuard rg = guard(ty);
checkCacheable(ty);

if (auto i = get<IntersectionType>(ty))
return foldl<IntersectionType>(begin(i), end(i), &TypeReducer::intersectionType);
Expand All @@ -176,6 +185,7 @@ TypePackId TypeReducer::reduce(TypePackId tp)
return tp;

RecursionGuard rg = guard(tp);
checkCacheable(tp);

TypePackIterator it = begin(tp);

Expand Down Expand Up @@ -213,6 +223,14 @@ std::optional<TypeId> TypeReducer::intersectionType(TypeId left, TypeId right)
return right; // any & T ~ T
else if (get<AnyType>(right))
return left; // T & any ~ T
else if (get<FreeType>(left))
return std::nullopt; // 'a & T ~ 'a & T
else if (get<FreeType>(right))
return std::nullopt; // T & 'a ~ T & 'a
else if (get<GenericType>(left))
return std::nullopt; // G & T ~ G & T
else if (get<GenericType>(right))
return std::nullopt; // T & G ~ T & G
else if (get<ErrorType>(left))
return std::nullopt; // error & T ~ error & T
else if (get<ErrorType>(right))
Expand Down Expand Up @@ -701,6 +719,32 @@ RecursionGuard TypeReducer::guard(TypePackId tp)
return RecursionGuard{&depth, FInt::LuauTypeReductionRecursionLimit, &seen};
}

void TypeReducer::checkCacheable(TypeId ty)
{
if (!cacheOk)
return;

ty = follow(ty);

// Only does shallow check, the TypeReducer itself already does deep traversal.
if (get<FreeType>(ty) || get<BlockedType>(ty) || get<PendingExpansionType>(ty))
cacheOk = false;
else if (auto tt = get<TableType>(ty); tt && (tt->state == TableState::Free || tt->state == TableState::Unsealed))
cacheOk = false;
}

void TypeReducer::checkCacheable(TypePackId tp)
{
if (!cacheOk)
return;

tp = follow(tp);

// Only does shallow check, the TypeReducer itself already does deep traversal.
if (get<FreeTypePack>(tp) || get<BlockedTypePack>(tp))
cacheOk = false;
}

} // namespace

TypeReduction::TypeReduction(NotNull<TypeArena> arena, NotNull<BuiltinTypes> builtinTypes, NotNull<InternalErrorReporter> handle)
Expand All @@ -715,64 +759,60 @@ std::optional<TypeId> TypeReduction::reduce(TypeId ty)
if (auto found = cachedTypes.find(ty))
return *found;

if (auto reduced = reduceImpl(ty))
{
cachedTypes[ty] = *reduced;
return *reduced;
}
auto [reducedTy, cacheOk] = reduceImpl(ty);
if (cacheOk)
cachedTypes[ty] = *reducedTy;

return std::nullopt;
return reducedTy;
}

std::optional<TypePackId> TypeReduction::reduce(TypePackId tp)
{
if (auto found = cachedTypePacks.find(tp))
return *found;

if (auto reduced = reduceImpl(tp))
{
cachedTypePacks[tp] = *reduced;
return *reduced;
}
auto [reducedTp, cacheOk] = reduceImpl(tp);
if (cacheOk)
cachedTypePacks[tp] = *reducedTp;

return std::nullopt;
return reducedTp;
}

std::optional<TypeId> TypeReduction::reduceImpl(TypeId ty)
std::pair<std::optional<TypeId>, bool> TypeReduction::reduceImpl(TypeId ty)
{
if (FFlag::DebugLuauDontReduceTypes)
return ty;
return {ty, false};

if (hasExceededCartesianProductLimit(ty))
return std::nullopt;
return {std::nullopt, false};

try
{
TypeReducer reducer{arena, builtinTypes, handle};
return reducer.reduce(ty);
return {reducer.reduce(ty), reducer.cacheOk};
}
catch (const RecursionLimitException&)
{
return std::nullopt;
return {std::nullopt, false};
}
}

std::optional<TypePackId> TypeReduction::reduceImpl(TypePackId tp)
std::pair<std::optional<TypePackId>, bool> TypeReduction::reduceImpl(TypePackId tp)
{
if (FFlag::DebugLuauDontReduceTypes)
return tp;
return {tp, false};

if (hasExceededCartesianProductLimit(tp))
return std::nullopt;
return {std::nullopt, false};

try
{
TypeReducer reducer{arena, builtinTypes, handle};
return reducer.reduce(tp);
return {reducer.reduce(tp), reducer.cacheOk};
}
catch (const RecursionLimitException&)
{
return std::nullopt;
return {std::nullopt, false};
}
}

Expand Down
15 changes: 1 addition & 14 deletions Ast/src/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@
LUAU_FASTINTVARIABLE(LuauRecursionLimit, 1000)
LUAU_FASTINTVARIABLE(LuauParseErrorLimit, 100)

LUAU_FASTFLAGVARIABLE(LuauFixNamedFunctionParse, false)
LUAU_DYNAMIC_FASTFLAGVARIABLE(LuaReportParseWrongNamedType, false)

bool lua_telemetry_parsed_named_non_function_type = false;

LUAU_FASTFLAGVARIABLE(LuauErrorDoubleHexPrefix, false)
LUAU_DYNAMIC_FASTFLAGVARIABLE(LuaReportParseIntegerIssues, false)

Expand Down Expand Up @@ -1423,30 +1418,22 @@ AstTypeOrPack Parser::parseFunctionTypeAnnotation(bool allowPack)

AstArray<AstType*> paramTypes = copy(params);

if (FFlag::LuauFixNamedFunctionParse && !names.empty())
if (!names.empty())
forceFunctionType = true;

bool returnTypeIntroducer = lexer.current().type == Lexeme::SkinnyArrow || lexer.current().type == ':';

// Not a function at all. Just a parenthesized type. Or maybe a type pack with a single element
if (params.size() == 1 && !varargAnnotation && !forceFunctionType && !returnTypeIntroducer)
{
if (DFFlag::LuaReportParseWrongNamedType && !names.empty())
lua_telemetry_parsed_named_non_function_type = true;

if (allowPack)
return {{}, allocator.alloc<AstTypePackExplicit>(begin.location, AstTypeList{paramTypes, nullptr})};
else
return {params[0], {}};
}

if (!forceFunctionType && !returnTypeIntroducer && allowPack)
{
if (DFFlag::LuaReportParseWrongNamedType && !names.empty())
lua_telemetry_parsed_named_non_function_type = true;

return {{}, allocator.alloc<AstTypePackExplicit>(begin.location, AstTypeList{paramTypes, varargAnnotation})};
}

AstArray<std::optional<AstArgumentName>> paramNames = copy(names);

Expand Down
5 changes: 3 additions & 2 deletions CodeGen/include/Luau/AssemblyBuilderX64.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class AssemblyBuilderX64

void test(OperandX64 lhs, OperandX64 rhs);
void lea(OperandX64 lhs, OperandX64 rhs);
void setcc(ConditionX64 cond, OperandX64 op);

void push(OperandX64 op);
void pop(OperandX64 op);
Expand Down Expand Up @@ -189,8 +190,8 @@ class AssemblyBuilderX64
const char* name, OperandX64 dst, OperandX64 src1, OperandX64 src2, uint8_t imm8, uint8_t code, bool setW, uint8_t mode, uint8_t prefix);

// Instruction components
void placeRegAndModRegMem(OperandX64 lhs, OperandX64 rhs);
void placeModRegMem(OperandX64 rhs, uint8_t regop);
void placeRegAndModRegMem(OperandX64 lhs, OperandX64 rhs, int32_t extraCodeBytes = 0);
void placeModRegMem(OperandX64 rhs, uint8_t regop, int32_t extraCodeBytes = 0);
void placeRex(RegisterX64 op);
void placeRex(OperandX64 op);
void placeRexNoW(OperandX64 op);
Expand Down
Loading

0 comments on commit a5c6a38

Please sign in to comment.