Skip to content

Commit c755875

Browse files
Vighnesh-Vaatxealexmccordandyfriesenaviralg
authored
Sync to upstream/release/605 (#1118)
- Implemented [Require by String with Relative Paths](https://github.com/luau-lang/rfcs/blob/master/docs/new-require-by-string-semantics.md) RFC - Implemented [Require by String with Aliases](https://github.com/luau-lang/rfcs/blob/master/docs/require-by-string-aliases.md) RFC with support for `paths` and `alias` arrays in .luarc - Added SUBRK and DIVRK bytecode instructions to speed up constant-number and constant/number operations - Added `--vector-lib`, `--vector-ctor` and `--vector-type` options to luau-compile to support code with vectors New Solver - Correctness fixes to subtyping - Improvements to dataflow analysis Native Code Generation - Added bytecode analysis pass to predict type tags used in operations - Fixed rare cases of numerical loops being generated without an interrupt instruction - Restored optimization data propagation into the linear block - Duplicate buffer length checks are optimized away Miscellaneous - Small performance improvements to new non-strict mode - Introduced more scripts for fuzzing Luau and processing the results, including fuzzer build support for CMake Co-authored-by: Alexander McCord <[email protected]> Co-authored-by: Andy Friesen <[email protected]> Co-authored-by: Aviral Goel <[email protected]> Co-authored-by: David Cope <[email protected]> Co-authored-by: Lily Brown <[email protected]> Co-authored-by: Vighnesh Vijay <[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: Aviral Goel <[email protected]> Co-authored-by: David Cope <[email protected]> Co-authored-by: Lily Brown <[email protected]> Co-authored-by: Vyacheslav Egorov <[email protected]>
1 parent 89b437b commit c755875

File tree

128 files changed

+3896
-979
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

128 files changed

+3896
-979
lines changed

Analysis/include/Luau/Constraint.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ struct InstantiationConstraint
4949
TypeId superType;
5050
};
5151

52-
// iteratee is iterable
53-
// iterators is the iteration types.
52+
// variables ~ iterate iterator
53+
// Unpack the iterator, figure out what types it iterates over, and bind those types to variables.
5454
struct IterableConstraint
5555
{
5656
TypePackId iterator;

Analysis/include/Luau/ConstraintGenerator.h

+1
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ struct ConstraintGenerator
225225
Inference check(const ScopePtr& scope, AstExprConstantBool* bool_, std::optional<TypeId> expectedType, bool forceSingleton);
226226
Inference check(const ScopePtr& scope, AstExprLocal* local);
227227
Inference check(const ScopePtr& scope, AstExprGlobal* global);
228+
Inference checkIndexName(const ScopePtr& scope, const RefinementKey* key, AstExpr* indexee, std::string index);
228229
Inference check(const ScopePtr& scope, AstExprIndexName* indexName);
229230
Inference check(const ScopePtr& scope, AstExprIndexExpr* indexExpr);
230231
Inference check(const ScopePtr& scope, AstExprFunction* func, std::optional<TypeId> expectedType, bool generalize);

Analysis/include/Luau/Error.h

+9-1
Original file line numberDiff line numberDiff line change
@@ -372,13 +372,21 @@ struct CheckedFunctionCallError
372372
bool operator==(const CheckedFunctionCallError& rhs) const;
373373
};
374374

375+
struct NonStrictFunctionDefinitionError
376+
{
377+
std::string functionName;
378+
std::string argument;
379+
TypeId argumentType;
380+
bool operator==(const NonStrictFunctionDefinitionError& rhs) const;
381+
};
382+
375383
using TypeErrorData = Variant<TypeMismatch, UnknownSymbol, UnknownProperty, NotATable, CannotExtendTable, OnlyTablesCanHaveMethods,
376384
DuplicateTypeDefinition, CountMismatch, FunctionDoesNotTakeSelf, FunctionRequiresSelf, OccursCheckFailed, UnknownRequire,
377385
IncorrectGenericParameterCount, SyntaxError, CodeTooComplex, UnificationTooComplex, UnknownPropButFoundLikeProp, GenericError, InternalError,
378386
CannotCallNonFunction, ExtraInformation, DeprecatedApiUsed, ModuleHasCyclicDependency, IllegalRequire, FunctionExitsWithoutReturning,
379387
DuplicateGenericParameter, CannotInferBinaryOperation, MissingProperties, SwappedGenericTypeParameter, OptionalValueAccess, MissingUnionProperty,
380388
TypesAreUnrelated, NormalizationTooComplex, TypePackMismatch, DynamicPropertyLookupOnClassesUnsafe, UninhabitedTypeFamily,
381-
UninhabitedTypePackFamily, WhereClauseNeeded, PackWhereClauseNeeded, CheckedFunctionCallError>;
389+
UninhabitedTypePackFamily, WhereClauseNeeded, PackWhereClauseNeeded, CheckedFunctionCallError, NonStrictFunctionDefinitionError>;
382390

383391
struct TypeErrorSummary
384392
{

Analysis/include/Luau/Subtyping.h

+9-3
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,17 @@ enum class SubtypingVariance
3232
// Used for an empty key. Should never appear in actual code.
3333
Invalid,
3434
Covariant,
35+
// This is used to identify cases where we have a covariant + a
36+
// contravariant reason and we need to merge them.
37+
Contravariant,
3538
Invariant,
3639
};
3740

3841
struct SubtypingReasoning
3942
{
43+
// The path, relative to the _root subtype_, where subtyping failed.
4044
Path subPath;
45+
// The path, relative to the _root supertype_, where subtyping failed.
4146
Path superPath;
4247
SubtypingVariance variance = SubtypingVariance::Covariant;
4348

@@ -49,6 +54,9 @@ struct SubtypingReasoningHash
4954
size_t operator()(const SubtypingReasoning& r) const;
5055
};
5156

57+
using SubtypingReasonings = DenseHashSet<SubtypingReasoning, SubtypingReasoningHash>;
58+
static const SubtypingReasoning kEmptyReasoning = SubtypingReasoning{TypePath::kEmpty, TypePath::kEmpty, SubtypingVariance::Invalid};
59+
5260
struct SubtypingResult
5361
{
5462
bool isSubtype = false;
@@ -58,8 +66,7 @@ struct SubtypingResult
5866

5967
/// The reason for isSubtype to be false. May not be present even if
6068
/// isSubtype is false, depending on the input types.
61-
DenseHashSet<SubtypingReasoning, SubtypingReasoningHash> reasoning{
62-
SubtypingReasoning{TypePath::kEmpty, TypePath::kEmpty, SubtypingVariance::Invalid}};
69+
SubtypingReasonings reasoning{kEmptyReasoning};
6370

6471
SubtypingResult& andAlso(const SubtypingResult& other);
6572
SubtypingResult& orElse(const SubtypingResult& other);
@@ -69,7 +76,6 @@ struct SubtypingResult
6976
SubtypingResult& withBothPath(TypePath::Path path);
7077
SubtypingResult& withSubPath(TypePath::Path path);
7178
SubtypingResult& withSuperPath(TypePath::Path path);
72-
SubtypingResult& withVariance(SubtypingVariance variance);
7379

7480
// Only negates the `isSubtype`.
7581
static SubtypingResult negate(const SubtypingResult& result);

Analysis/include/Luau/Unifier2.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ struct Unifier2
6161
bool unify(TypeId subTy, const UnionType* superUnion);
6262
bool unify(const IntersectionType* subIntersection, TypeId superTy);
6363
bool unify(TypeId subTy, const IntersectionType* superIntersection);
64-
bool unify(const TableType* subTable, const TableType* superTable);
64+
bool unify(TableType* subTable, const TableType* superTable);
6565
bool unify(const MetatableType* subMetatable, const MetatableType* superMetatable);
6666

6767
// TODO think about this one carefully. We don't do unions or intersections of type packs

Analysis/src/ConstraintGenerator.cpp

+36-18
Original file line numberDiff line numberDiff line change
@@ -750,17 +750,18 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatForIn* forI
750750

751751
for (AstLocal* var : forIn->vars)
752752
{
753-
TypeId ty = nullptr;
754-
if (var->annotation)
755-
ty = resolveType(loopScope, var->annotation, /*inTypeArguments*/ false);
756-
else
757-
ty = freshType(loopScope);
758-
759-
loopScope->bindings[var] = Binding{ty, var->location};
760-
761753
TypeId assignee = arena->addType(BlockedType{});
762754
variableTypes.push_back(assignee);
763755

756+
if (var->annotation)
757+
{
758+
TypeId annotationTy = resolveType(loopScope, var->annotation, /*inTypeArguments*/ false);
759+
loopScope->bindings[var] = Binding{annotationTy, var->location};
760+
addConstraint(scope, var->location, SubtypeConstraint{assignee, annotationTy});
761+
}
762+
else
763+
loopScope->bindings[var] = Binding{assignee, var->location};
764+
764765
DefId def = dfg->getDef(var);
765766
loopScope->lvalueTypes[def] = assignee;
766767
}
@@ -1439,9 +1440,6 @@ InferencePack ConstraintGenerator::checkPack(const ScopePtr& scope, AstExprCall*
14391440
module->astOriginalCallTypes[call->func] = fnType;
14401441
module->astOriginalCallTypes[call] = fnType;
14411442

1442-
TypeId instantiatedFnType = arena->addType(BlockedType{});
1443-
addConstraint(scope, call->location, InstantiationConstraint{instantiatedFnType, fnType});
1444-
14451443
Checkpoint argBeginCheckpoint = checkpoint(this);
14461444

14471445
std::vector<TypeId> args;
@@ -1740,12 +1738,11 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprGlobal* globa
17401738
}
17411739
}
17421740

1743-
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprIndexName* indexName)
1741+
Inference ConstraintGenerator::checkIndexName(const ScopePtr& scope, const RefinementKey* key, AstExpr* indexee, std::string index)
17441742
{
1745-
TypeId obj = check(scope, indexName->expr).ty;
1743+
TypeId obj = check(scope, indexee).ty;
17461744
TypeId result = arena->addType(BlockedType{});
17471745

1748-
const RefinementKey* key = dfg->getRefinementKey(indexName);
17491746
if (key)
17501747
{
17511748
if (auto ty = lookup(scope.get(), key->def))
@@ -1754,18 +1751,31 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprIndexName* in
17541751
scope->rvalueRefinements[key->def] = result;
17551752
}
17561753

1757-
addConstraint(scope, indexName->expr->location, HasPropConstraint{result, obj, indexName->index.value});
1754+
addConstraint(scope, indexee->location, HasPropConstraint{result, obj, std::move(index)});
17581755

17591756
if (key)
17601757
return Inference{result, refinementArena.proposition(key, builtinTypes->truthyType)};
17611758
else
17621759
return Inference{result};
17631760
}
17641761

1762+
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprIndexName* indexName)
1763+
{
1764+
const RefinementKey* key = dfg->getRefinementKey(indexName);
1765+
return checkIndexName(scope, key, indexName->expr, indexName->index.value);
1766+
}
1767+
17651768
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprIndexExpr* indexExpr)
17661769
{
1770+
if (auto constantString = indexExpr->index->as<AstExprConstantString>())
1771+
{
1772+
const RefinementKey* key = dfg->getRefinementKey(indexExpr);
1773+
return checkIndexName(scope, key, indexExpr->expr, constantString->value.data);
1774+
}
1775+
17671776
TypeId obj = check(scope, indexExpr->expr).ty;
17681777
TypeId indexType = check(scope, indexExpr->index).ty;
1778+
17691779
TypeId result = freshType(scope);
17701780

17711781
const RefinementKey* key = dfg->getRefinementKey(indexExpr);
@@ -3079,15 +3089,23 @@ struct GlobalPrepopulator : AstVisitor
30793089
{
30803090
}
30813091

3092+
bool visit(AstExprGlobal* global) override
3093+
{
3094+
if (auto ty = globalScope->lookup(global->name))
3095+
{
3096+
DefId def = dfg->getDef(global);
3097+
globalScope->lvalueTypes[def] = *ty;
3098+
}
3099+
3100+
return true;
3101+
}
3102+
30823103
bool visit(AstStatFunction* function) override
30833104
{
30843105
if (AstExprGlobal* g = function->name->as<AstExprGlobal>())
30853106
{
30863107
TypeId bt = arena->addType(BlockedType{});
30873108
globalScope->bindings[g->name] = Binding{bt};
3088-
3089-
DefId def = dfg->getDef(function->name);
3090-
globalScope->lvalueTypes[def] = bt;
30913109
}
30923110

30933111
return true;

Analysis/src/ConstraintSolver.cpp

+14-42
Original file line numberDiff line numberDiff line change
@@ -1263,9 +1263,6 @@ bool ConstraintSolver::tryDispatch(const SetPropConstraint& c, NotNull<const Con
12631263
if (isBlocked(subjectType))
12641264
return block(subjectType, constraint);
12651265

1266-
if (!force && get<FreeType>(subjectType))
1267-
return block(subjectType, constraint);
1268-
12691266
std::optional<TypeId> existingPropType = subjectType;
12701267
for (const std::string& segment : c.path)
12711268
{
@@ -1301,25 +1298,13 @@ bool ConstraintSolver::tryDispatch(const SetPropConstraint& c, NotNull<const Con
13011298

13021299
if (get<FreeType>(subjectType))
13031300
{
1304-
TypeId ty = freshType(arena, builtinTypes, constraint->scope);
1305-
1306-
// Mint a chain of free tables per c.path
1307-
for (auto it = rbegin(c.path); it != rend(c.path); ++it)
1308-
{
1309-
TableType t{TableState::Free, TypeLevel{}, constraint->scope};
1310-
t.props[*it] = {ty};
1311-
1312-
ty = arena->addType(std::move(t));
1313-
}
1314-
1315-
LUAU_ASSERT(ty);
1316-
1317-
bind(subjectType, ty);
1318-
if (follow(c.resultType) != follow(ty))
1319-
bind(c.resultType, ty);
1320-
unblock(subjectType, constraint->location);
1321-
unblock(c.resultType, constraint->location);
1322-
return true;
1301+
/*
1302+
* This should never occur because lookupTableProp() will add bounds to
1303+
* any free types it encounters. There will always be an
1304+
* existingPropType if the subject is free.
1305+
*/
1306+
LUAU_ASSERT(false);
1307+
return false;
13231308
}
13241309
else if (auto ttv = getMutable<TableType>(subjectType))
13251310
{
@@ -1328,7 +1313,7 @@ bool ConstraintSolver::tryDispatch(const SetPropConstraint& c, NotNull<const Con
13281313
LUAU_ASSERT(!subjectType->persistent);
13291314

13301315
ttv->props[c.path[0]] = Property{c.propType};
1331-
bind(c.resultType, c.subjectType);
1316+
bind(c.resultType, subjectType);
13321317
unblock(c.resultType, constraint->location);
13331318
return true;
13341319
}
@@ -1337,26 +1322,12 @@ bool ConstraintSolver::tryDispatch(const SetPropConstraint& c, NotNull<const Con
13371322
LUAU_ASSERT(!subjectType->persistent);
13381323

13391324
updateTheTableType(builtinTypes, NotNull{arena}, subjectType, c.path, c.propType);
1340-
bind(c.resultType, c.subjectType);
1341-
unblock(subjectType, constraint->location);
1342-
unblock(c.resultType, constraint->location);
1343-
return true;
1344-
}
1345-
else
1346-
{
1347-
bind(c.resultType, subjectType);
1348-
unblock(c.resultType, constraint->location);
1349-
return true;
13501325
}
13511326
}
1352-
else
1353-
{
1354-
// Other kinds of types don't change shape when properties are assigned
1355-
// to them. (if they allow properties at all!)
1356-
bind(c.resultType, subjectType);
1357-
unblock(c.resultType, constraint->location);
1358-
return true;
1359-
}
1327+
1328+
bind(c.resultType, subjectType);
1329+
unblock(c.resultType, constraint->location);
1330+
return true;
13601331
}
13611332

13621333
bool ConstraintSolver::tryDispatch(const SetIndexerConstraint& c, NotNull<const Constraint> constraint, bool force)
@@ -1908,6 +1879,7 @@ bool ConstraintSolver::tryDispatchIterableFunction(
19081879
TypeId retIndex;
19091880
if (isNil(firstIndexTy) || isOptional(firstIndexTy))
19101881
{
1882+
// FIXME freshType is suspect here
19111883
firstIndex = arena->addType(UnionType{{freshType(arena, builtinTypes, constraint->scope), builtinTypes->nilType}});
19121884
retIndex = firstIndex;
19131885
}
@@ -1949,7 +1921,7 @@ bool ConstraintSolver::tryDispatchIterableFunction(
19491921
modifiedNextRetHead.push_back(*it);
19501922

19511923
TypePackId modifiedNextRetPack = arena->addTypePack(std::move(modifiedNextRetHead), it.tail());
1952-
auto psc = pushConstraint(constraint->scope, constraint->location, PackSubtypeConstraint{c.variables, modifiedNextRetPack});
1924+
auto psc = pushConstraint(constraint->scope, constraint->location, UnpackConstraint{c.variables, modifiedNextRetPack});
19531925
inheritBlocks(constraint, psc);
19541926

19551927
return true;

Analysis/src/Error.cpp

+15
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,12 @@ struct ErrorConverter
533533
return "Function '" + e.checkedFunctionName + "' expects '" + toString(e.expected) + "' at argument #" + std::to_string(e.argumentIndex) +
534534
", but got '" + Luau::toString(e.passed) + "'";
535535
}
536+
537+
std::string operator()(const NonStrictFunctionDefinitionError& e) const
538+
{
539+
return "Argument " + e.argument + " with type '" + toString(e.argumentType) + "' in function '" + e.functionName +
540+
"' is used in a way that will run time error";
541+
}
536542
};
537543

538544
struct InvalidNameChecker
@@ -861,6 +867,11 @@ bool CheckedFunctionCallError::operator==(const CheckedFunctionCallError& rhs) c
861867
argumentIndex == rhs.argumentIndex;
862868
}
863869

870+
bool NonStrictFunctionDefinitionError::operator==(const NonStrictFunctionDefinitionError& rhs) const
871+
{
872+
return functionName == rhs.functionName && argument == rhs.argument && argumentType == rhs.argumentType;
873+
}
874+
864875
std::string toString(const TypeError& error)
865876
{
866877
return toString(error, TypeErrorToStringOptions{});
@@ -1032,6 +1043,10 @@ void copyError(T& e, TypeArena& destArena, CloneState& cloneState)
10321043
e.expected = clone(e.expected);
10331044
e.passed = clone(e.passed);
10341045
}
1046+
else if constexpr (std::is_same_v<T, NonStrictFunctionDefinitionError>)
1047+
{
1048+
e.argumentType = clone(e.argumentType);
1049+
}
10351050
else
10361051
static_assert(always_false_v<T>, "Non-exhaustive type switch");
10371052
}

Analysis/src/IostreamHelpers.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,9 @@ static void errorToString(std::ostream& stream, const T& err)
204204
else if constexpr (std::is_same_v<T, CheckedFunctionCallError>)
205205
stream << "CheckedFunctionCallError { expected = '" << toString(err.expected) << "', passed = '" << toString(err.passed)
206206
<< "', checkedFunctionName = " << err.checkedFunctionName << ", argumentIndex = " << std::to_string(err.argumentIndex) << " }";
207+
else if constexpr (std::is_same_v<T, NonStrictFunctionDefinitionError>)
208+
stream << "NonStrictFunctionDefinitionError { functionName = '" + err.functionName + "', argument = '" + err.argument +
209+
"', argumentType = '" + toString(err.argumentType) + "' }";
207210
else
208211
static_assert(always_false_v<T>, "Non-exhaustive type switch");
209212
}

0 commit comments

Comments
 (0)