Skip to content

Commit

Permalink
Sync to upstream/release/640 (#1374)
Browse files Browse the repository at this point in the history
### What's new

* Fixed many of the false positive errors in indexing of table unions
and table intersections
* It is now possible to run custom checks over Luau AST during
typechecking by setting `customModuleCheck` in `FrontendOptions`
* Fixed codegen issue on arm, where number->vector cast could corrupt
that number value for the next time it's read

### New Solver

* `error` type now behaves as the bottom type during subtyping checks
* Fixed the scope that is used in subtyping with generic types
* Fixed `astOriginalCallTypes` table often used by LSP to match the old
solver

---

### Internal Contributors

Co-authored-by: Aaron Weiss <[email protected]>
Co-authored-by: Andy Friesen <[email protected]>
Co-authored-by: Vighnesh Vijay <[email protected]>
Co-authored-by: Vyacheslav Egorov <[email protected]>
  • Loading branch information
5 people authored Aug 23, 2024
1 parent 1dde4de commit d518d14
Show file tree
Hide file tree
Showing 52 changed files with 1,381 additions and 972 deletions.
4 changes: 4 additions & 0 deletions Analysis/include/Luau/Frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ struct FrontendOptions

// When true, some internal complexity limits will be scaled down for modules that miss the limit set by moduleTimeLimitSec
bool applyInternalLimitScaling = false;

// An optional callback which is called for every *dirty* module was checked
// Is multi-threaded typechecking is used, this callback might be called from multiple threads and has to be thread-safe
std::function<void(const SourceModule& sourceModule, const Luau::Module& module)> customModuleCheck;
};

struct CheckResult
Expand Down
144 changes: 96 additions & 48 deletions Analysis/include/Luau/Subtyping.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ struct Subtyping
NotNull<Normalizer> normalizer;
NotNull<InternalErrorReporter> iceReporter;

NotNull<Scope> scope;
TypeCheckLimits limits;

enum class Variance
Expand All @@ -144,8 +143,7 @@ struct Subtyping
NotNull<BuiltinTypes> builtinTypes,
NotNull<TypeArena> typeArena,
NotNull<Normalizer> normalizer,
NotNull<InternalErrorReporter> iceReporter,
NotNull<Scope> scope
NotNull<InternalErrorReporter> iceReporter
);

Subtyping(const Subtyping&) = delete;
Expand All @@ -164,83 +162,133 @@ struct Subtyping
// TODO cyclic types
// TODO recursion limits

SubtypingResult isSubtype(TypeId subTy, TypeId superTy);
SubtypingResult isSubtype(TypePackId subTy, TypePackId superTy);
SubtypingResult isSubtype(TypeId subTy, TypeId superTy, NotNull<Scope> scope);
SubtypingResult isSubtype(TypePackId subTy, TypePackId superTy, NotNull<Scope> scope);

private:
DenseHashMap<std::pair<TypeId, TypeId>, SubtypingResult, TypePairHash> resultCache{{}};

SubtypingResult cache(SubtypingEnvironment& env, SubtypingResult res, TypeId subTy, TypeId superTy);

SubtypingResult isCovariantWith(SubtypingEnvironment& env, TypeId subTy, TypeId superTy);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, TypePackId subTy, TypePackId superTy);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, TypeId subTy, TypeId superTy, NotNull<Scope> scope);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, TypePackId subTp, TypePackId superTp, NotNull<Scope> scope);

template<typename SubTy, typename SuperTy>
SubtypingResult isContravariantWith(SubtypingEnvironment& env, SubTy&& subTy, SuperTy&& superTy);
SubtypingResult isContravariantWith(SubtypingEnvironment& env, SubTy&& subTy, SuperTy&& superTy, NotNull<Scope> scope);

template<typename SubTy, typename SuperTy>
SubtypingResult isInvariantWith(SubtypingEnvironment& env, SubTy&& subTy, SuperTy&& superTy);
SubtypingResult isInvariantWith(SubtypingEnvironment& env, SubTy&& subTy, SuperTy&& superTy, NotNull<Scope> scope);

template<typename SubTy, typename SuperTy>
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TryPair<const SubTy*, const SuperTy*>& pair);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TryPair<const SubTy*, const SuperTy*>& pair, NotNull<Scope> scope);

template<typename SubTy, typename SuperTy>
SubtypingResult isContravariantWith(SubtypingEnvironment& env, const TryPair<const SubTy*, const SuperTy*>& pair);
SubtypingResult isContravariantWith(SubtypingEnvironment& env, const TryPair<const SubTy*, const SuperTy*>& pair, NotNull<Scope>);

template<typename SubTy, typename SuperTy>
SubtypingResult isInvariantWith(SubtypingEnvironment& env, const TryPair<const SubTy*, const SuperTy*>& pair);

SubtypingResult isCovariantWith(SubtypingEnvironment& env, TypeId subTy, const UnionType* superUnion);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const UnionType* subUnion, TypeId superTy);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, TypeId subTy, const IntersectionType* superIntersection);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const IntersectionType* subIntersection, TypeId superTy);

SubtypingResult isCovariantWith(SubtypingEnvironment& env, const NegationType* subNegation, TypeId superTy);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TypeId subTy, const NegationType* superNegation);

SubtypingResult isCovariantWith(SubtypingEnvironment& env, const PrimitiveType* subPrim, const PrimitiveType* superPrim);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const SingletonType* subSingleton, const PrimitiveType* superPrim);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const SingletonType* subSingleton, const SingletonType* superSingleton);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TableType* subTable, const TableType* superTable);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const MetatableType* subMt, const MetatableType* superMt);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const MetatableType* subMt, const TableType* superTable);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const ClassType* subClass, const ClassType* superClass);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, TypeId subTy, const ClassType* subClass, TypeId superTy, const TableType* superTable);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const FunctionType* subFunction, const FunctionType* superFunction);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TableType* subTable, const PrimitiveType* superPrim);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const PrimitiveType* subPrim, const TableType* superTable);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const SingletonType* subSingleton, const TableType* superTable);

SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TableIndexer& subIndexer, const TableIndexer& superIndexer);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const Property& subProperty, const Property& superProperty, const std::string& name);
SubtypingResult isInvariantWith(SubtypingEnvironment& env, const TryPair<const SubTy*, const SuperTy*>& pair, NotNull<Scope>);

SubtypingResult isCovariantWith(SubtypingEnvironment& env, TypeId subTy, const UnionType* superUnion, NotNull<Scope> scope);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const UnionType* subUnion, TypeId superTy, NotNull<Scope> scope);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, TypeId subTy, const IntersectionType* superIntersection, NotNull<Scope> scope);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const IntersectionType* subIntersection, TypeId superTy, NotNull<Scope> scope);

SubtypingResult isCovariantWith(SubtypingEnvironment& env, const NegationType* subNegation, TypeId superTy, NotNull<Scope> scope);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TypeId subTy, const NegationType* superNegation, NotNull<Scope> scope);

SubtypingResult isCovariantWith(SubtypingEnvironment& env, const PrimitiveType* subPrim, const PrimitiveType* superPrim, NotNull<Scope> scope);
SubtypingResult isCovariantWith(
SubtypingEnvironment& env,
const SingletonType* subSingleton,
const PrimitiveType* superPrim,
NotNull<Scope> scope
);
SubtypingResult isCovariantWith(
SubtypingEnvironment& env,
const SingletonType* subSingleton,
const SingletonType* superSingleton,
NotNull<Scope> scope
);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TableType* subTable, const TableType* superTable, NotNull<Scope> scope);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const MetatableType* subMt, const MetatableType* superMt, NotNull<Scope> scope);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const MetatableType* subMt, const TableType* superTable, NotNull<Scope> scope);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const ClassType* subClass, const ClassType* superClass, NotNull<Scope> scope);
SubtypingResult
isCovariantWith(SubtypingEnvironment& env, TypeId subTy, const ClassType* subClass, TypeId superTy, const TableType* superTable, NotNull<Scope>);
SubtypingResult isCovariantWith(
SubtypingEnvironment& env,
const FunctionType* subFunction,
const FunctionType* superFunction,
NotNull<Scope> scope
);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TableType* subTable, const PrimitiveType* superPrim, NotNull<Scope> scope);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const PrimitiveType* subPrim, const TableType* superTable, NotNull<Scope> scope);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const SingletonType* subSingleton, const TableType* superTable, NotNull<Scope> scope);

SubtypingResult isCovariantWith(
SubtypingEnvironment& env,
const TableIndexer& subIndexer,
const TableIndexer& superIndexer,
NotNull<Scope> scope
);
SubtypingResult
isCovariantWith(SubtypingEnvironment& env, const Property& subProperty, const Property& superProperty, const std::string& name, NotNull<Scope>);

SubtypingResult isCovariantWith(
SubtypingEnvironment& env,
const std::shared_ptr<const NormalizedType>& subNorm,
const std::shared_ptr<const NormalizedType>& superNorm
const std::shared_ptr<const NormalizedType>& superNorm,
NotNull<Scope> scope
);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const NormalizedClassType& subClass, const NormalizedClassType& superClass);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const NormalizedClassType& subClass, const TypeIds& superTables);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const NormalizedStringType& subString, const NormalizedStringType& superString);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const NormalizedStringType& subString, const TypeIds& superTables);
SubtypingResult isCovariantWith(
SubtypingEnvironment& env,
const NormalizedFunctionType& subFunction,
const NormalizedFunctionType& superFunction
const NormalizedClassType& subClass,
const NormalizedClassType& superClass,
NotNull<Scope> scope
);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const NormalizedClassType& subClass, const TypeIds& superTables, NotNull<Scope> scope);
SubtypingResult isCovariantWith(
SubtypingEnvironment& env,
const NormalizedStringType& subString,
const NormalizedStringType& superString,
NotNull<Scope> scope
);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TypeIds& subTypes, const TypeIds& superTypes);
SubtypingResult isCovariantWith(
SubtypingEnvironment& env,
const NormalizedStringType& subString,
const TypeIds& superTables,
NotNull<Scope> scope
);
SubtypingResult
isCovariantWith(SubtypingEnvironment& env, const NormalizedFunctionType& subFunction, const NormalizedFunctionType& superFunction, NotNull<Scope>);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TypeIds& subTypes, const TypeIds& superTypes, NotNull<Scope> scope);

SubtypingResult isCovariantWith(SubtypingEnvironment& env, const VariadicTypePack* subVariadic, const VariadicTypePack* superVariadic);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TypeFunctionInstanceType* subFunctionInstance, const TypeId superTy);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TypeId subTy, const TypeFunctionInstanceType* superFunctionInstance);
SubtypingResult isCovariantWith(
SubtypingEnvironment& env,
const VariadicTypePack* subVariadic,
const VariadicTypePack* superVariadic,
NotNull<Scope> scope
);
SubtypingResult isCovariantWith(
SubtypingEnvironment& env,
const TypeFunctionInstanceType* subFunctionInstance,
const TypeId superTy,
NotNull<Scope> scope
);
SubtypingResult isCovariantWith(
SubtypingEnvironment& env,
const TypeId subTy,
const TypeFunctionInstanceType* superFunctionInstance,
NotNull<Scope> scope
);

bool bindGeneric(SubtypingEnvironment& env, TypeId subTp, TypeId superTp);
bool bindGeneric(SubtypingEnvironment& env, TypePackId subTp, TypePackId superTp);

template<typename T, typename Container>
TypeId makeAggregateType(const Container& container, TypeId orElse);

std::pair<TypeId, ErrorVec> handleTypeFunctionReductionResult(const TypeFunctionInstanceType* functionInstance);
std::pair<TypeId, ErrorVec> handleTypeFunctionReductionResult(const TypeFunctionInstanceType* functionInstance, NotNull<Scope> scope);

[[noreturn]] void unexpected(TypeId ty);
[[noreturn]] void unexpected(TypePackId tp);
Expand Down
17 changes: 10 additions & 7 deletions Analysis/src/AnyTypeSummary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

#include <stdio.h>

LUAU_FASTFLAGVARIABLE(StudioReportLuauAny, false);
LUAU_FASTFLAGVARIABLE(StudioReportLuauAny2, false);
LUAU_FASTINTVARIABLE(LuauAnySummaryRecursionLimit, 300);

LUAU_FASTFLAG(DebugLuauMagicTypes);
Expand Down Expand Up @@ -211,14 +211,17 @@ void AnyTypeSummary::visit(const Scope* scope, AstStatLocal* local, const Module
if (!maybeRequire)
continue;

if (isAnyCast(scope, local->values.data[posn], module, builtinTypes))
if (std::min(local->values.size - 1, posn) < head.size())
{
TelemetryTypePair types;
if (isAnyCast(scope, local->values.data[posn], module, builtinTypes))
{
TelemetryTypePair types;

types.inferredType = toString(head[std::min(local->values.size - 1, posn)]);
types.inferredType = toString(head[std::min(local->values.size - 1, posn)]);

TypeInfo ti{Pattern::Casts, toString(ctxNode), types};
typeInfo.push_back(ti);
TypeInfo ti{Pattern::Casts, toString(ctxNode), types};
typeInfo.push_back(ti);
}
}
}
else
Expand Down Expand Up @@ -292,7 +295,7 @@ void AnyTypeSummary::visit(const Scope* scope, AstStatAssign* assign, const Modu
types.annotatedType = toString(tp);

auto loc = std::min(assign->vars.size - 1, posn);
if (head.size() >= assign->vars.size)
if (head.size() >= assign->vars.size && posn < head.size())
{
types.inferredType = toString(head[posn]);
}
Expand Down
4 changes: 2 additions & 2 deletions Analysis/src/Autocomplete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,9 @@ static bool checkTypeMatch(TypeId subTy, TypeId superTy, NotNull<Scope> scope, T

if (FFlag::DebugLuauDeferredConstraintResolution)
{
Subtyping subtyping{builtinTypes, NotNull{typeArena}, NotNull{&normalizer}, NotNull{&iceReporter}, scope};
Subtyping subtyping{builtinTypes, NotNull{typeArena}, NotNull{&normalizer}, NotNull{&iceReporter}};

return subtyping.isSubtype(subTy, superTy).isSubtype;
return subtyping.isSubtype(subTy, superTy, scope).isSubtype;
}
else
{
Expand Down
2 changes: 1 addition & 1 deletion Analysis/src/ConstraintGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1793,7 +1793,7 @@ InferencePack ConstraintGenerator::checkPack(const ScopePtr& scope, AstExprCall*

std::vector<std::optional<TypeId>> expectedTypesForCall = getExpectedCallTypesForFunctionOverloads(fnType);

module->astOriginalCallTypes[call] = fnType;
module->astOriginalCallTypes[call->func] = fnType;

Checkpoint argBeginCheckpoint = checkpoint(this);

Expand Down
12 changes: 8 additions & 4 deletions Analysis/src/Frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ LUAU_FASTFLAGVARIABLE(DebugLuauForbidInternalTypes, false)
LUAU_FASTFLAGVARIABLE(DebugLuauForceStrictMode, false)
LUAU_FASTFLAGVARIABLE(DebugLuauForceNonStrictMode, false)
LUAU_FASTFLAGVARIABLE(LuauSourceModuleUpdatedWithSelectedMode, false)
LUAU_DYNAMIC_FASTFLAGVARIABLE(LuauRunCustomModuleChecks, false)

LUAU_FASTFLAG(StudioReportLuauAny)
LUAU_FASTFLAG(StudioReportLuauAny2)

namespace Luau
{
Expand Down Expand Up @@ -511,7 +512,7 @@ CheckResult Frontend::check(const ModuleName& name, std::optional<FrontendOption
if (item.name == name)
checkResult.lintResult = item.module->lintResult;

if (FFlag::StudioReportLuauAny && item.options.retainFullTypeGraphs)
if (FFlag::StudioReportLuauAny2 && item.options.retainFullTypeGraphs)
{
if (item.module)
{
Expand Down Expand Up @@ -1040,6 +1041,9 @@ void Frontend::checkBuildQueueItem(BuildQueueItem& item)
item.stats.timeCheck += duration;
item.stats.filesStrict += 1;

if (DFFlag::LuauRunCustomModuleChecks && item.options.customModuleCheck)
item.options.customModuleCheck(sourceModule, *moduleForAutocomplete);

item.module = moduleForAutocomplete;
return;
}
Expand All @@ -1057,8 +1061,8 @@ void Frontend::checkBuildQueueItem(BuildQueueItem& item)
item.stats.filesStrict += mode == Mode::Strict;
item.stats.filesNonstrict += mode == Mode::Nonstrict;

if (module == nullptr)
throw InternalCompilerError("Frontend::check produced a nullptr module for " + item.name, item.name);
if (DFFlag::LuauRunCustomModuleChecks && item.options.customModuleCheck)
item.options.customModuleCheck(sourceModule, *module);

if (FFlag::DebugLuauDeferredConstraintResolution && mode == Mode::NoCheck)
module->errors.clear();
Expand Down
Loading

0 comments on commit d518d14

Please sign in to comment.