Skip to content

Commit

Permalink
Fix type registration with solver v2
Browse files Browse the repository at this point in the history
remove legacy arg

start work with the tests

current changes
  • Loading branch information
checkraisefold committed Sep 28, 2024
1 parent e415039 commit e788b68
Show file tree
Hide file tree
Showing 17 changed files with 275 additions and 83 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
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
45 changes: 42 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 Expand Up @@ -271,6 +296,20 @@ std::optional<lsp::Hover> WorkspaceFolder::hover(const lsp::HoverParams& params)
return std::nullopt;
type = Luau::follow(*type);

// TODO: Dirty hack for invalid definitionModuleName on type aliases for solver v2!
// Remove after https://github.com/luau-lang/luau/issues/1441 is closed!
/*auto typeVal = type.value();
if (auto ttv = Luau::get<Luau::TableType>(*type); ttv && ttv->definitionModuleName.empty() && FFlag::LuauSolverV2)
{
auto name = ttv->name;
if (typeVal->owningArena && typeVal->owningArena->owningModule)
documentationLocation = {typeVal->owningArena->owningModule->name, node->location};
auto locations = scope->typeAliasLocations;
if (name && (locations.find(name.value()) != locations.end()))
documentationLocation = {moduleName, locations.at(name.value())};
}*/

if (!documentationSymbol)
documentationSymbol = type.value()->documentationSymbol;

Expand Down
11 changes: 7 additions & 4 deletions src/platform/roblox/RobloxCompletion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include "LSP/Completion.hpp"
#include "LSP/Workspace.hpp"

LUAU_FASTFLAG(LuauSolverV2)

static constexpr const char* COMMON_SERVICES[] = {
"Players",
"ReplicatedStorage",
Expand Down Expand Up @@ -254,7 +256,8 @@ const char* RobloxPlatform::handleSortText(
return SortText::PrioritisedSuggestion;

// If calling a property on ServiceProvider, then prioritise these properties
if (auto dataModelType = frontend.globalsForAutocomplete.globalScope->lookupType("ServiceProvider");
auto& completionGlobals = FFlag::LuauSolverV2 ? frontend.globals : frontend.globalsForAutocomplete;
if (auto dataModelType = completionGlobals.globalScope->lookupType("ServiceProvider");
dataModelType && Luau::get<Luau::ClassType>(dataModelType->type) && entry.containingClass &&
Luau::isSubclass(entry.containingClass.value(), Luau::get<Luau::ClassType>(dataModelType->type)) && !entry.wrongIndexType)
{
Expand All @@ -264,9 +267,9 @@ const char* RobloxPlatform::handleSortText(
}

// If calling a property on an Instance, then prioritise these properties
else if (auto instanceType = frontend.globalsForAutocomplete.globalScope->lookupType("Instance");
instanceType && Luau::get<Luau::ClassType>(instanceType->type) && entry.containingClass &&
Luau::isSubclass(entry.containingClass.value(), Luau::get<Luau::ClassType>(instanceType->type)) && !entry.wrongIndexType)
else if (auto instanceType = completionGlobals.globalScope->lookupType("Instance");
instanceType && Luau::get<Luau::ClassType>(instanceType->type) && entry.containingClass &&
Luau::isSubclass(entry.containingClass.value(), Luau::get<Luau::ClassType>(instanceType->type)) && !entry.wrongIndexType)
{
if (auto it = std::find(std::begin(COMMON_INSTANCE_PROPERTIES), std::end(COMMON_INSTANCE_PROPERTIES), name);
it != std::end(COMMON_INSTANCE_PROPERTIES))
Expand Down
Loading

0 comments on commit e788b68

Please sign in to comment.