Skip to content

Commit

Permalink
Fix type registration with solver v2
Browse files Browse the repository at this point in the history
  • Loading branch information
checkraisefold committed Oct 26, 2024
1 parent d35acff commit 056a926
Show file tree
Hide file tree
Showing 19 changed files with 345 additions and 141 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,12 @@ jobs:
cmake ..
cmake --build . --target Luau.LanguageServer.Test -j 3
- name: Run Tests
- name: Run Tests (Old Solver)
run: ${{ matrix.test-path }}

- name: Run Tests (New Solver)
run: ${{ matrix.test-path }} --new-solver

types_smoketest:
name: Types Smoketest
runs-on: ubuntu-20.04
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/build
.vscode/settings.json
/.vs
out/
.cache
.idea
.DS_Store
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Changed

- Sync to upstream Luau 0.647
- Fixed inlay hints, autocompletion, type registration, hover types/documentation, and some crashes for cases where the new solver is enabled

## [1.33.1] - 2024-10-05

Expand Down
18 changes: 11 additions & 7 deletions src/AnalyzeCli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <vector>

LUAU_FASTFLAG(DebugLuauTimeTracing)
LUAU_FASTFLAG(LuauSolverV2)

enum class ReportFormat
{
Expand Down Expand Up @@ -174,7 +175,7 @@ int startAnalyze(const argparse::ArgumentParser& program)
if (std::filesystem::is_directory(path))
{
for (std::filesystem::recursive_directory_iterator next(path, std::filesystem::directory_options::skip_permission_denied), end;
next != end; ++next)
next != end; ++next)
{
try
{
Expand Down Expand Up @@ -307,8 +308,9 @@ int startAnalyze(const argparse::ArgumentParser& program)

Luau::Frontend frontend(&fileResolver, &fileResolver, frontendOptions);

Luau::registerBuiltinGlobals(frontend, frontend.globals, /* typeCheckForAutocomplete = */ false);
Luau::registerBuiltinGlobals(frontend, frontend.globalsForAutocomplete, /* typeCheckForAutocomplete = */ true);
Luau::registerBuiltinGlobals(frontend, frontend.globals);
if (!FFlag::LuauSolverV2)
Luau::registerBuiltinGlobals(frontend, frontend.globalsForAutocomplete);

for (auto& definitionsPath : definitionsPaths)
{
Expand All @@ -325,7 +327,7 @@ int startAnalyze(const argparse::ArgumentParser& program)
return 1;
}

auto loadResult = types::registerDefinitions(frontend, frontend.globals, *definitionsContents, /* typeCheckForAutocomplete = */ false);
auto loadResult = types::registerDefinitions(frontend, frontend.globals, *definitionsContents);
if (!loadResult.success)
{
fprintf(stderr, "Failed to load definitions\n");
Expand Down Expand Up @@ -359,8 +361,9 @@ int startAnalyze(const argparse::ArgumentParser& program)
{
robloxPlatform->updateSourceNodeMap(sourceMapContents.value());

robloxPlatform->handleSourcemapUpdate(
frontend, frontend.globals, !program.is_used("--no-strict-dm-types") && client.configuration.diagnostics.strictDatamodelTypes);
bool expressiveTypes =
(program.is_used("--no-strict-dm-types") && client.configuration.diagnostics.strictDatamodelTypes) || FFlag::LuauSolverV2;
robloxPlatform->handleSourcemapUpdate(frontend, frontend.globals, expressiveTypes);
}
}
else
Expand All @@ -371,7 +374,8 @@ int startAnalyze(const argparse::ArgumentParser& program)
}

Luau::freeze(frontend.globals.globalTypes);
Luau::freeze(frontend.globalsForAutocomplete.globalTypes);
if (!FFlag::LuauSolverV2)
Luau::freeze(frontend.globalsForAutocomplete.globalTypes);

int failed = 0;

Expand Down
2 changes: 1 addition & 1 deletion src/DocumentationParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ std::optional<std::string> WorkspaceFolder::getDocumentationForType(const Luau::
{
return printMoonwaveDocumentation(getComments(ftv->definition->definitionModuleName.value(), ftv->definition->definitionLocation));
}
else if (auto ttv = Luau::get<Luau::TableType>(followedTy); ttv && !ttv->definitionModuleName.empty())
else if (auto ttv = Luau::get<Luau::TableType>(followedTy); ttv)
{
return printMoonwaveDocumentation(getComments(ttv->definitionModuleName, ttv->definitionLocation));
}
Expand Down
40 changes: 37 additions & 3 deletions src/LuauExt.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include <optional>
#include <utility>

#include "Luau/Type.h"
#include "Platform/LSPPlatform.hpp"
#include "Luau/BuiltinDefinitions.h"
#include "Luau/ToString.h"
Expand Down Expand Up @@ -51,11 +53,10 @@ std::optional<nlohmann::json> parseDefinitionsFileMetadata(const std::string& de
return std::nullopt;
}

Luau::LoadDefinitionFileResult registerDefinitions(
Luau::Frontend& frontend, Luau::GlobalTypes& globals, const std::string& definitions, bool typeCheckForAutocomplete)
Luau::LoadDefinitionFileResult registerDefinitions(Luau::Frontend& frontend, Luau::GlobalTypes& globals, const std::string& definitions)
{
// TODO: packageName shouldn't just be "@roblox"
return frontend.loadDefinitionFile(globals, globals.globalScope, definitions, "@roblox", /* captureComments = */ false, typeCheckForAutocomplete);
return frontend.loadDefinitionFile(globals, globals.globalScope, definitions, "@roblox", /* captureComments = */ false);
}

using NameOrExpr = std::variant<std::string, Luau::AstExpr*>;
Expand Down Expand Up @@ -428,6 +429,39 @@ lsp::Diagnostic createParseErrorDiagnostic(const Luau::ParseError& error, const
return diagnostic;
}

// TODO: Dirty hack for invalid definitionModuleName on type aliases for solver v2!
// Remove after https://github.com/luau-lang/luau/issues/1441 is closed!
std::optional<Luau::ModuleName> lookupTypeDefinitionModule(Luau::TypeId type)
{
if (!FFlag::LuauSolverV2)
{
return Luau::getDefinitionModuleName(type);
}

type = Luau::follow(type);
if (auto ttv = Luau::get<Luau::TableType>(type); ttv && ttv->definitionModuleName.empty())
{
if (type->owningArena && type->owningArena->owningModule)
return type->owningArena->owningModule->name;
}

return Luau::getDefinitionModuleName(type);
}

std::optional<Luau::Location> lookupTypeDefinitionModuleLocation(Luau::TypeId type, Luau::ModulePtr module)
{
type = Luau::follow(type);
auto types = module->astResolvedTypes;
for (auto it = types.begin(); it != types.end(); ++it)
{
if (it->second == type)
{
return it->first->location;
}
}
return std::nullopt;
}

// Based on upstream, except we use containsClosed
struct FindExprOrLocalClosed : public Luau::AstVisitor
{
Expand Down
16 changes: 10 additions & 6 deletions src/Workspace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,10 +285,12 @@ void WorkspaceFolder::registerTypes()
{
LUAU_TIMETRACE_SCOPE("WorkspaceFolder::initialize", "LSP");
client->sendTrace("workspace initialization: registering Luau globals");
Luau::registerBuiltinGlobals(frontend, frontend.globals, /* typeCheckForAutocomplete = */ false);
Luau::registerBuiltinGlobals(frontend, frontend.globalsForAutocomplete, /* typeCheckForAutocomplete = */ true);
Luau::registerBuiltinGlobals(frontend, frontend.globals);
if (!FFlag::LuauSolverV2)
Luau::registerBuiltinGlobals(frontend, frontend.globalsForAutocomplete);

Luau::attachTag(Luau::getGlobalBinding(frontend.globalsForAutocomplete, "require"), "Require");
auto& tagRegisterGlobals = FFlag::LuauSolverV2 ? frontend.globals : frontend.globalsForAutocomplete;
Luau::attachTag(Luau::getGlobalBinding(tagRegisterGlobals, "require"), "Require");

if (client->definitionsFiles.empty())
client->sendLogMessage(lsp::MessageType::Warning, "No definitions file provided by client");
Expand All @@ -314,8 +316,9 @@ void WorkspaceFolder::registerTypes()
client->sendTrace("workspace initialization: parsing definitions file metadata COMPLETED", json(definitionsFileMetadata).dump());

client->sendTrace("workspace initialization: registering types definition");
auto result = types::registerDefinitions(frontend, frontend.globals, *definitionsContents, /* typeCheckForAutocomplete = */ false);
types::registerDefinitions(frontend, frontend.globalsForAutocomplete, *definitionsContents, /* typeCheckForAutocomplete = */ true);
auto result = types::registerDefinitions(frontend, frontend.globals, *definitionsContents);
if (!FFlag::LuauSolverV2)
types::registerDefinitions(frontend, frontend.globalsForAutocomplete, *definitionsContents);
client->sendTrace("workspace initialization: registering types definition COMPLETED");

client->sendTrace("workspace: applying platform mutations on definitions");
Expand Down Expand Up @@ -347,7 +350,8 @@ void WorkspaceFolder::registerTypes()
}
}
Luau::freeze(frontend.globals.globalTypes);
Luau::freeze(frontend.globalsForAutocomplete.globalTypes);
if (!FFlag::LuauSolverV2)
Luau::freeze(frontend.globalsForAutocomplete.globalTypes);
}

void WorkspaceFolder::setupWithConfiguration(const ClientConfiguration& configuration)
Expand Down
6 changes: 4 additions & 2 deletions src/include/LSP/LuauExt.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ bool isMetamethod(const Luau::Name& name);

std::optional<nlohmann::json> parseDefinitionsFileMetadata(const std::string& definitions);

Luau::LoadDefinitionFileResult registerDefinitions(
Luau::Frontend& frontend, Luau::GlobalTypes& globals, const std::string& definitions, bool typeCheckForAutocomplete = false);
Luau::LoadDefinitionFileResult registerDefinitions(Luau::Frontend& frontend, Luau::GlobalTypes& globals, const std::string& definitions);

using NameOrExpr = std::variant<std::string, Luau::AstExpr*>;

Expand Down Expand Up @@ -69,6 +68,9 @@ bool isRequire(const Luau::AstExpr* expr);
bool isMethod(const Luau::FunctionType* ftv);
bool isOverloadedMethod(Luau::TypeId ty);

std::optional<Luau::ModuleName> lookupTypeDefinitionModule(Luau::TypeId type);
std::optional<Luau::Location> lookupTypeDefinitionModuleLocation(Luau::TypeId type, Luau::ModulePtr module);

struct FindImportsVisitor : public Luau::AstVisitor
{
private:
Expand Down
21 changes: 17 additions & 4 deletions src/operations/Completion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include "LSP/LuauExt.hpp"
#include "LSP/DocumentationParser.hpp"

LUAU_FASTFLAG(LuauSolverV2)

void WorkspaceFolder::endAutocompletion(const lsp::CompletionParams& params)
{
auto moduleName = fileResolver.getModuleName(params.textDocument.uri);
Expand Down Expand Up @@ -254,8 +256,8 @@ static const char* sortText(const Luau::Frontend& frontend, const std::string& n
return SortText::AutoImports;

// If the entry is `loadstring`, deprioritise it
if (auto it = frontend.globalsForAutocomplete.globalScope->bindings.find(Luau::AstName("loadstring"));
it != frontend.globalsForAutocomplete.globalScope->bindings.end())
auto& completionGlobals = FFlag::LuauSolverV2 ? frontend.globals : frontend.globalsForAutocomplete;
if (auto it = completionGlobals.globalScope->bindings.find(Luau::AstName("loadstring")); it != completionGlobals.globalScope->bindings.end())
{
if (entry.type == it->second.typeId)
return SortText::Deprioritized;
Expand Down Expand Up @@ -369,10 +371,21 @@ std::optional<std::string> WorkspaceFolder::getDocumentationForAutocompleteEntry
if (parentTy)
{
// parentTy might be an intersected type, find the actual base ttv
if (auto propInformation = lookupProp(*parentTy, name))
auto followedTy = Luau::follow(*parentTy);
if (auto propInformation = lookupProp(followedTy, name))
definitionModuleName = Luau::getDefinitionModuleName(propInformation->first);
else
definitionModuleName = Luau::getDefinitionModuleName(*parentTy);
definitionModuleName = Luau::getDefinitionModuleName(followedTy);

// TODO: Dirty hack for invalid definitionModuleName on type aliases for solver v2!
// Remove after https://github.com/luau-lang/luau/issues/1441 is closed!
if (FFlag::LuauSolverV2 && !definitionModuleName)
{
if (followedTy->owningArena && followedTy->owningArena->owningModule)
{
definitionModuleName = followedTy->owningArena->owningModule->name;
}
}
}
}
}
Expand Down
31 changes: 28 additions & 3 deletions src/operations/Hover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,18 @@ std::optional<lsp::Hover> WorkspaceFolder::hover(const lsp::HoverParams& params)
auto typeFun = scope->lookupType(typeName);
if (!typeFun)
return std::nullopt;

// TODO: Dirty hack for invalid definitionModuleName on type aliases for solver v2!
// Remove after https://github.com/luau-lang/luau/issues/1441 is closed!
if (FFlag::LuauSolverV2 && typeFun->type)
{
auto followedType = Luau::follow(typeFun->type);
auto name = lookupTypeDefinitionModule(followedType);
auto location = lookupTypeDefinitionModuleLocation(followedType, module);
if (name && location)
documentationLocation = {name.value(), location.value()};
}

typeAliasInformation = std::make_pair(typeName, *typeFun);
type = typeFun->type;
}
Expand All @@ -177,7 +189,7 @@ std::optional<lsp::Hover> WorkspaceFolder::hover(const lsp::HoverParams& params)
if (prop.location.containsClosed(position))
{
auto parentType = Luau::follow(*tableTy);
if (auto definitionModuleName = Luau::getDefinitionModuleName(parentType))
if (auto definitionModuleName = lookupTypeDefinitionModule(parentType))
documentationLocation = {definitionModuleName.value(), prop.location};
auto resolvedProperty = lookupProp(parentType, prop.name.value);
if (resolvedProperty)
Expand All @@ -197,7 +209,20 @@ std::optional<lsp::Hover> WorkspaceFolder::hover(const lsp::HoverParams& params)
else if (auto local = exprOrLocal.getLocal()) // TODO: can we just use node here instead of also calling exprOrLocal?
{
type = scope->lookup(local);
documentationLocation = {moduleName, local->location};
// TODO: Dirty hack for invalid definitionModuleName on type aliases for solver v2!
// Remove after https://github.com/luau-lang/luau/issues/1441 is closed!
if (FFlag::LuauSolverV2 && type)
{
auto followedType = Luau::follow(*type);
auto name = lookupTypeDefinitionModule(followedType);
auto location = lookupTypeDefinitionModuleLocation(followedType, module);
if (name && location)
documentationLocation = {name.value(), location.value()};
else
documentationLocation = {moduleName, local->location};
}
else
documentationLocation = {moduleName, local->location};
}
else if (auto expr = exprOrLocal.getExpr())
{
Expand Down Expand Up @@ -233,7 +258,7 @@ std::optional<lsp::Hover> WorkspaceFolder::hover(const lsp::HoverParams& params)
{
auto [baseTy, prop] = propInformation.value();
type = prop.type();
if (auto definitionModuleName = Luau::getDefinitionModuleName(baseTy))
if (auto definitionModuleName = lookupTypeDefinitionModule(baseTy))
{
if (prop.location)
documentationLocation = {definitionModuleName.value(), prop.location.value()};
Expand Down
Loading

0 comments on commit 056a926

Please sign in to comment.