Skip to content

Commit e905e30

Browse files
vrn-snaatxeandyfriesenhgoldsteinVighnesh-V
authored
Sync to upstream/release/652 (#1525)
## What's new? * Add support for mixed-mode type checking, which allows modules checked in the old type solver to be checked and autocompleted by the new one. * Generalize `RequireResolver` to support require-by-string semantics in `luau-analyze`. * Fix a bug in incremental autocomplete where `DefId`s associated with index expressions were not correctly picked up. * Fix a bug that prevented "complex" types in generic parameters (for example, `local x: X<(() -> ())?>`). ### Issues fixed * #1507 * #1518 --- Internal Contributors: Co-authored-by: Aaron Weiss <[email protected]> Co-authored-by: Andy Friesen <[email protected]> Co-authored-by: Hunter Goldstein <[email protected]> Co-authored-by: Varun Saini <[email protected]> Co-authored-by: Vighnesh Vijay <[email protected]>
1 parent d1025d0 commit e905e30

Some content is hidden

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

44 files changed

+1750
-905
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
/luau
1414
/luau-tests
1515
/luau-analyze
16+
/luau-bytecode
1617
/luau-compile
1718
__pycache__
1819
.cache

Analysis/include/Luau/DataFlowGraph.h

-19
Original file line numberDiff line numberDiff line change
@@ -126,25 +126,6 @@ struct DataFlowGraphBuilder
126126
NotNull<InternalErrorReporter> handle
127127
);
128128

129-
/**
130-
* Takes a stale graph along with a list of scopes, a small fragment of the ast, and a cursor position
131-
* and constructs the DataFlowGraph for just that fragment. This method will fabricate defs in the final
132-
* DFG for things that have been referenced and exist in the stale dfg.
133-
* For example, the fragment local z = x + y will populate defs for x and y from the stale graph.
134-
* @param staleGraph - the old DFG
135-
* @param scopes - the old DfgScopes in the graph
136-
* @param fragment - the Ast Fragment to re-build the root for
137-
* @param cursorPos - the current location of the cursor - used to determine which scope we are currently in
138-
* @param handle - for internal compiler errors
139-
*/
140-
static DataFlowGraph updateGraph(
141-
const DataFlowGraph& staleGraph,
142-
const std::vector<std::unique_ptr<DfgScope>>& scopes,
143-
AstStatBlock* fragment,
144-
const Position& cursorPos,
145-
NotNull<InternalErrorReporter> handle
146-
);
147-
148129
private:
149130
DataFlowGraphBuilder() = default;
150131

Analysis/include/Luau/FragmentAutocomplete.h

+10-3
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,20 @@ struct FragmentAutocompleteResult
4949

5050
FragmentAutocompleteAncestryResult findAncestryForFragmentParse(AstStatBlock* root, const Position& cursorPos);
5151

52-
FragmentParseResult parseFragment(const SourceModule& srcModule, std::string_view src, const Position& cursorPos);
52+
FragmentParseResult parseFragment(
53+
const SourceModule& srcModule,
54+
std::string_view src,
55+
const Position& cursorPos,
56+
std::optional<Position> fragmentEndPosition
57+
);
5358

5459
FragmentTypeCheckResult typecheckFragment(
5560
Frontend& frontend,
5661
const ModuleName& moduleName,
5762
const Position& cursorPos,
5863
std::optional<FrontendOptions> opts,
59-
std::string_view src
64+
std::string_view src,
65+
std::optional<Position> fragmentEndPosition
6066
);
6167

6268
FragmentAutocompleteResult fragmentAutocomplete(
@@ -65,7 +71,8 @@ FragmentAutocompleteResult fragmentAutocomplete(
6571
const ModuleName& moduleName,
6672
Position cursorPosition,
6773
std::optional<FrontendOptions> opts,
68-
StringCompletionCallback callback
74+
StringCompletionCallback callback,
75+
std::optional<Position> fragmentEndPosition = std::nullopt
6976
);
7077

7178

Analysis/include/Luau/Module.h

+3
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ struct Module
6868
{
6969
~Module();
7070

71+
// TODO: Clip this when we clip FFlagLuauSolverV2
72+
bool checkedInNewSolver = false;
73+
7174
ModuleName name;
7275
std::string humanReadableName;
7376

Analysis/src/AutocompleteCore.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
LUAU_FASTFLAG(LuauSolverV2)
2323
LUAU_FASTFLAGVARIABLE(AutocompleteRequirePathSuggestions2)
24-
LUAU_DYNAMIC_FASTINT(LuauTypeSolverRelease)
2524
LUAU_FASTINT(LuauTypeInferIterationLimit)
2625
LUAU_FASTINT(LuauTypeInferRecursionLimit)
2726

Analysis/src/BuiltinDefinitions.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
*/
3030

3131
LUAU_FASTFLAG(LuauSolverV2)
32-
LUAU_DYNAMIC_FASTINT(LuauTypeSolverRelease)
3332
LUAU_FASTFLAGVARIABLE(LuauTypestateBuiltins2)
3433
LUAU_FASTFLAGVARIABLE(LuauStringFormatArityFix)
3534

Analysis/src/ConstraintGenerator.cpp

+51-158
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ LUAU_FASTINT(LuauCheckRecursionLimit)
3232
LUAU_FASTFLAG(DebugLuauLogSolverToJson)
3333
LUAU_FASTFLAG(DebugLuauMagicTypes)
3434
LUAU_FASTFLAG(DebugLuauEqSatSimplification)
35-
LUAU_DYNAMIC_FASTINT(LuauTypeSolverRelease)
3635
LUAU_FASTFLAG(LuauTypestateBuiltins2)
3736

3837
LUAU_FASTFLAGVARIABLE(LuauNewSolverVisitErrorExprLvalues)
@@ -225,8 +224,7 @@ void ConstraintGenerator::visitModuleRoot(AstStatBlock* block)
225224

226225
Checkpoint start = checkpoint(this);
227226

228-
ControlFlow cf =
229-
DFInt::LuauTypeSolverRelease >= 646 ? visitBlockWithoutChildScope(scope, block) : visitBlockWithoutChildScope_DEPRECATED(scope, block);
227+
ControlFlow cf = visitBlockWithoutChildScope(scope, block);
230228
if (cf == ControlFlow::None)
231229
addConstraint(scope, block->location, PackSubtypeConstraint{builtinTypes->emptyTypePack, rootScope->returnType});
232230

@@ -876,123 +874,6 @@ ControlFlow ConstraintGenerator::visitBlockWithoutChildScope(const ScopePtr& sco
876874
return firstControlFlow.value_or(ControlFlow::None);
877875
}
878876

879-
ControlFlow ConstraintGenerator::visitBlockWithoutChildScope_DEPRECATED(const ScopePtr& scope, AstStatBlock* block)
880-
{
881-
RecursionCounter counter{&recursionCount};
882-
883-
if (recursionCount >= FInt::LuauCheckRecursionLimit)
884-
{
885-
reportCodeTooComplex(block->location);
886-
return ControlFlow::None;
887-
}
888-
889-
std::unordered_map<Name, Location> aliasDefinitionLocations;
890-
891-
// In order to enable mutually-recursive type aliases, we need to
892-
// populate the type bindings before we actually check any of the
893-
// alias statements.
894-
for (AstStat* stat : block->body)
895-
{
896-
if (auto alias = stat->as<AstStatTypeAlias>())
897-
{
898-
if (scope->exportedTypeBindings.count(alias->name.value) || scope->privateTypeBindings.count(alias->name.value))
899-
{
900-
auto it = aliasDefinitionLocations.find(alias->name.value);
901-
LUAU_ASSERT(it != aliasDefinitionLocations.end());
902-
reportError(alias->location, DuplicateTypeDefinition{alias->name.value, it->second});
903-
continue;
904-
}
905-
906-
// A type alias might have no name if the code is syntactically
907-
// illegal. We mustn't prepopulate anything in this case.
908-
if (alias->name == kParseNameError || alias->name == "typeof")
909-
continue;
910-
911-
ScopePtr defnScope = childScope(alias, scope);
912-
913-
TypeId initialType = arena->addType(BlockedType{});
914-
TypeFun initialFun{initialType};
915-
916-
for (const auto& [name, gen] : createGenerics(defnScope, alias->generics, /* useCache */ true))
917-
{
918-
initialFun.typeParams.push_back(gen);
919-
}
920-
921-
for (const auto& [name, genPack] : createGenericPacks(defnScope, alias->genericPacks, /* useCache */ true))
922-
{
923-
initialFun.typePackParams.push_back(genPack);
924-
}
925-
926-
if (alias->exported)
927-
scope->exportedTypeBindings[alias->name.value] = std::move(initialFun);
928-
else
929-
scope->privateTypeBindings[alias->name.value] = std::move(initialFun);
930-
931-
astTypeAliasDefiningScopes[alias] = defnScope;
932-
aliasDefinitionLocations[alias->name.value] = alias->location;
933-
}
934-
else if (auto function = stat->as<AstStatTypeFunction>())
935-
{
936-
// If a type function w/ same name has already been defined, error for having duplicates
937-
if (scope->exportedTypeBindings.count(function->name.value) || scope->privateTypeBindings.count(function->name.value))
938-
{
939-
auto it = aliasDefinitionLocations.find(function->name.value);
940-
LUAU_ASSERT(it != aliasDefinitionLocations.end());
941-
reportError(function->location, DuplicateTypeDefinition{function->name.value, it->second});
942-
continue;
943-
}
944-
945-
if (scope->parent != globalScope)
946-
{
947-
reportError(function->location, GenericError{"Local user-defined functions are not supported yet"});
948-
continue;
949-
}
950-
951-
ScopePtr defnScope = childScope(function, scope);
952-
953-
// Create TypeFunctionInstanceType
954-
955-
std::vector<TypeId> typeParams;
956-
typeParams.reserve(function->body->args.size);
957-
958-
std::vector<GenericTypeDefinition> quantifiedTypeParams;
959-
quantifiedTypeParams.reserve(function->body->args.size);
960-
961-
for (size_t i = 0; i < function->body->args.size; i++)
962-
{
963-
std::string name = format("T%zu", i);
964-
TypeId ty = arena->addType(GenericType{name});
965-
typeParams.push_back(ty);
966-
967-
GenericTypeDefinition genericTy{ty};
968-
quantifiedTypeParams.push_back(genericTy);
969-
}
970-
971-
if (std::optional<std::string> error = typeFunctionRuntime->registerFunction(function))
972-
reportError(function->location, GenericError{*error});
973-
974-
TypeId typeFunctionTy =
975-
arena->addType(TypeFunctionInstanceType{NotNull{&builtinTypeFunctions().userFunc}, std::move(typeParams), {}, function->name, {}});
976-
977-
TypeFun typeFunction{std::move(quantifiedTypeParams), typeFunctionTy};
978-
979-
// Set type bindings and definition locations for this user-defined type function
980-
scope->privateTypeBindings[function->name.value] = std::move(typeFunction);
981-
aliasDefinitionLocations[function->name.value] = function->location;
982-
}
983-
}
984-
985-
std::optional<ControlFlow> firstControlFlow;
986-
for (AstStat* stat : block->body)
987-
{
988-
ControlFlow cf = visit(scope, stat);
989-
if (cf != ControlFlow::None && !firstControlFlow)
990-
firstControlFlow = cf;
991-
}
992-
993-
return firstControlFlow.value_or(ControlFlow::None);
994-
}
995-
996877
ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStat* stat)
997878
{
998879
RecursionLimiter limiter{&recursionCount, FInt::LuauCheckRecursionLimit};
@@ -1336,10 +1217,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatRepeat* rep
13361217
{
13371218
ScopePtr repeatScope = childScope(repeat, scope);
13381219

1339-
if (DFInt::LuauTypeSolverRelease >= 646)
1340-
visitBlockWithoutChildScope(repeatScope, repeat->body);
1341-
else
1342-
visitBlockWithoutChildScope_DEPRECATED(repeatScope, repeat->body);
1220+
visitBlockWithoutChildScope(repeatScope, repeat->body);
13431221

13441222
check(repeatScope, repeat->condition);
13451223

@@ -1513,8 +1391,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatBlock* bloc
15131391
{
15141392
ScopePtr innerScope = childScope(block, scope);
15151393

1516-
ControlFlow flow = DFInt::LuauTypeSolverRelease >= 646 ? visitBlockWithoutChildScope(innerScope, block)
1517-
: visitBlockWithoutChildScope_DEPRECATED(innerScope, block);
1394+
ControlFlow flow = visitBlockWithoutChildScope(innerScope, block);
15181395

15191396
// An AstStatBlock has linear control flow, i.e. one entry and one exit, so we can inherit
15201397
// all the changes to the environment occurred by the statements in that block.
@@ -1705,7 +1582,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatTypeFunctio
17051582
TypeFun typeFunction = bindingIt->second;
17061583

17071584
// Adding typeAliasExpansionConstraint on user-defined type function for the constraint solver
1708-
if (auto typeFunctionTy = get<TypeFunctionInstanceType>(DFInt::LuauTypeSolverRelease >= 646 ? follow(typeFunction.type) : typeFunction.type))
1585+
if (auto typeFunctionTy = get<TypeFunctionInstanceType>(follow(typeFunction.type)))
17091586
{
17101587
TypeId expansionTy = arena->addType(PendingExpansionType{{}, function->name, typeFunctionTy->typeArguments, typeFunctionTy->packArguments});
17111588
addConstraint(scope, function->location, TypeAliasExpansionConstraint{/* target */ expansionTy});
@@ -3026,32 +2903,12 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprTable* expr,
30262903
{
30272904
Unifier2 unifier{arena, builtinTypes, NotNull{scope.get()}, ice};
30282905
std::vector<TypeId> toBlock;
3029-
if (DFInt::LuauTypeSolverRelease >= 648)
3030-
{
3031-
// This logic is incomplete as we want to re-run this
3032-
// _after_ blocked types have resolved, but this
3033-
// allows us to do some bidirectional inference.
3034-
toBlock = findBlockedTypesIn(expr, NotNull{&module->astTypes});
3035-
if (toBlock.empty())
3036-
{
3037-
matchLiteralType(
3038-
NotNull{&module->astTypes},
3039-
NotNull{&module->astExpectedTypes},
3040-
builtinTypes,
3041-
arena,
3042-
NotNull{&unifier},
3043-
*expectedType,
3044-
ty,
3045-
expr,
3046-
toBlock
3047-
);
3048-
// The visitor we ran prior should ensure that there are no
3049-
// blocked types that we would encounter while matching on
3050-
// this expression.
3051-
LUAU_ASSERT(toBlock.empty());
3052-
}
3053-
}
3054-
else
2906+
// This logic is incomplete as we want to re-run this
2907+
// _after_ blocked types have resolved, but this
2908+
// allows us to do some bidirectional inference.
2909+
toBlock = findBlockedTypesIn(expr, NotNull{&module->astTypes});
2910+
2911+
if (toBlock.empty())
30552912
{
30562913
matchLiteralType(
30572914
NotNull{&module->astTypes},
@@ -3063,7 +2920,11 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprTable* expr,
30632920
ty,
30642921
expr,
30652922
toBlock
3066-
);
2923+
);
2924+
// The visitor we ran prior should ensure that there are no
2925+
// blocked types that we would encounter while matching on
2926+
// this expression.
2927+
LUAU_ASSERT(toBlock.empty());
30672928
}
30682929
}
30692930

@@ -3265,8 +3126,7 @@ ConstraintGenerator::FunctionSignature ConstraintGenerator::checkFunctionSignatu
32653126
void ConstraintGenerator::checkFunctionBody(const ScopePtr& scope, AstExprFunction* fn)
32663127
{
32673128
// If it is possible for execution to reach the end of the function, the return type must be compatible with ()
3268-
ControlFlow cf =
3269-
DFInt::LuauTypeSolverRelease >= 646 ? visitBlockWithoutChildScope(scope, fn->body) : visitBlockWithoutChildScope_DEPRECATED(scope, fn->body);
3129+
ControlFlow cf = visitBlockWithoutChildScope(scope, fn->body);
32703130
if (cf == ControlFlow::None)
32713131
addConstraint(scope, fn->location, PackSubtypeConstraint{builtinTypes->emptyTypePack, scope->returnType});
32723132
}
@@ -3745,11 +3605,18 @@ struct FragmentTypeCheckGlobalPrepopulator : AstVisitor
37453605
const NotNull<Scope> globalScope;
37463606
const NotNull<Scope> currentScope;
37473607
const NotNull<const DataFlowGraph> dfg;
3608+
const NotNull<TypeArena> arena;
37483609

3749-
FragmentTypeCheckGlobalPrepopulator(NotNull<Scope> globalScope, NotNull<Scope> currentScope, NotNull<const DataFlowGraph> dfg)
3610+
FragmentTypeCheckGlobalPrepopulator(
3611+
NotNull<Scope> globalScope,
3612+
NotNull<Scope> currentScope,
3613+
NotNull<const DataFlowGraph> dfg,
3614+
NotNull<TypeArena> arena
3615+
)
37503616
: globalScope(globalScope)
37513617
, currentScope(currentScope)
37523618
, dfg(dfg)
3619+
, arena(arena)
37533620
{
37543621
}
37553622

@@ -3761,6 +3628,32 @@ struct FragmentTypeCheckGlobalPrepopulator : AstVisitor
37613628
// We only want to write into the current scope the type of the global
37623629
currentScope->lvalueTypes[def] = *ty;
37633630
}
3631+
else if (auto ty = currentScope->lookup(global->name))
3632+
{
3633+
// We are trying to create a binding for a brand new function, so we actually do have to write it into the scope.
3634+
DefId def = dfg->getDef(global);
3635+
// We only want to write into the current scope the type of the global
3636+
currentScope->lvalueTypes[def] = *ty;
3637+
}
3638+
3639+
return true;
3640+
}
3641+
3642+
bool visit(AstStatFunction* function) override
3643+
{
3644+
if (AstExprGlobal* g = function->name->as<AstExprGlobal>())
3645+
{
3646+
if (auto ty = globalScope->lookup(g->name))
3647+
{
3648+
currentScope->bindings[g->name] = Binding{*ty};
3649+
}
3650+
else
3651+
{
3652+
// Hasn't existed since a previous typecheck
3653+
TypeId bt = arena->addType(BlockedType{});
3654+
currentScope->bindings[g->name] = Binding{bt};
3655+
}
3656+
}
37643657

37653658
return true;
37663659
}
@@ -3814,7 +3707,7 @@ struct GlobalPrepopulator : AstVisitor
38143707

38153708
void ConstraintGenerator::prepopulateGlobalScopeForFragmentTypecheck(const ScopePtr& globalScope, const ScopePtr& resumeScope, AstStatBlock* program)
38163709
{
3817-
FragmentTypeCheckGlobalPrepopulator gp{NotNull{globalScope.get()}, NotNull{resumeScope.get()}, dfg};
3710+
FragmentTypeCheckGlobalPrepopulator gp{NotNull{globalScope.get()}, NotNull{resumeScope.get()}, dfg, arena};
38183711
if (prepareModuleScope)
38193712
prepareModuleScope(module->name, resumeScope);
38203713
program->visit(&gp);

0 commit comments

Comments
 (0)