From 3e8b97b8c4f004f2f26508f634195bcc744e8887 Mon Sep 17 00:00:00 2001 From: JohnnyMorganz Date: Thu, 31 Mar 2022 16:17:54 +0100 Subject: [PATCH] Properly resolve a script's children to allow indexing --- RequireResolver.cpp | 21 +++++---- RequireResolver.h | 1 + main.cpp | 110 ++++++++++++++++++++++++++------------------ 3 files changed, 78 insertions(+), 54 deletions(-) diff --git a/RequireResolver.cpp b/RequireResolver.cpp index 498967b..e26abfa 100644 --- a/RequireResolver.cpp +++ b/RequireResolver.cpp @@ -241,15 +241,9 @@ std::optional RojoResolver::parseSourceMap(const std::filesys return std::nullopt; } -std::optional RojoResolver::resolveRequireToRealPath(const std::string& requirePath, const SourceNode& root) +std::optional RojoResolver::resolveRequireToSourceNode(const std::string& requirePath, const SourceNode& root) { auto pathParts = Luau::split(requirePath, '/'); - // auto root = pathParts.front(); - - // if (roots.find(std::string(root)) == roots.end()) - // return std::nullopt; - - // SourceNode currentNode = roots.at(std::string(root)); SourceNode currentNode = root; auto it = ++pathParts.begin(); // Skip first element @@ -266,12 +260,19 @@ std::optional RojoResolver::resolveRequireToRealPath(cons return std::nullopt; } - - it++; } - return currentNode.path; + return currentNode; +} + +std::optional RojoResolver::resolveRequireToRealPath(const std::string& requirePath, const SourceNode& root) +{ + if (auto node = RojoResolver::resolveRequireToSourceNode(requirePath, root)) + { + return node.value().path; + } + return std::nullopt; } std::optional RojoResolver::resolveRealPathToVirtual(const ResolvedSourceMap& sourceMap, const std::filesystem::path& filePath) diff --git a/RequireResolver.h b/RequireResolver.h index aa04c28..2daebd9 100644 --- a/RequireResolver.h +++ b/RequireResolver.h @@ -26,6 +26,7 @@ struct ResolvedSourceMap namespace RojoResolver { std::optional parseSourceMap(const std::filesystem::path& sourceMapPath); +std::optional resolveRequireToSourceNode(const std::string& requirePath, const SourceNode& root); std::optional resolveRequireToRealPath(const std::string& requirePath, const SourceNode& root); Luau::SourceCode::Type sourceCodeTypeFromPath(const std::filesystem::path& path); std::optional resolveRealPathToVirtual(const ResolvedSourceMap& sourceMap, const std::filesystem::path& filePath); diff --git a/main.cpp b/main.cpp index e27fbd5..c5535e9 100644 --- a/main.cpp +++ b/main.cpp @@ -129,6 +129,36 @@ bool isManagedModule(const Luau::ModuleName& name) return Luau::startsWith(name, "game/") || Luau::startsWith(name, "ProjectRoot/"); } +std::optional getCurrentModuleVirtualPath( + const Luau::ModuleName& name, ResolvedSourceMap sourceMap, std::optional stdinFilepath) +{ + if (isManagedModule(name)) + { + return name; + } + else + { + // name is a file path which we need to translate to a Rojo path + std::filesystem::path filePath = name; + if (name == "-") + { + if (stdinFilepath) + { + filePath = stdinFilepath.value(); + } + else + { + return std::nullopt; + } + } + auto virtualPath = RojoResolver::resolveRealPathToVirtual(sourceMap, filePath); + if (virtualPath) + return virtualPath.value(); + } + + return std::nullopt; +} + struct CliFileResolver : Luau::FileResolver { ResolvedSourceMap sourceMap; @@ -183,30 +213,9 @@ struct CliFileResolver : Luau::FileResolver if (g->name == "script") { - // Resolve the current path at context.name - if (isManagedModule(context->name)) + if (auto virtualPath = getCurrentModuleVirtualPath(context->name, sourceMap, stdinFilepath)) { - // We can just use this as the starting point - return Luau::ModuleInfo{context->name}; - } - else - { - // context->name is a file path which we need to translate to a Rojo path - std::filesystem::path filePath = context->name; - if (context->name == "-") - { - if (stdinFilepath) - { - filePath = stdinFilepath.value(); - } - else - { - return std::nullopt; - } - } - auto virtualPath = RojoResolver::resolveRealPathToVirtual(sourceMap, filePath); - if (virtualPath) - return Luau::ModuleInfo{virtualPath.value()}; + return Luau::ModuleInfo{virtualPath.value()}; } } } @@ -320,26 +329,16 @@ struct CliConfigResolver : Luau::ConfigResolver } }; -std::optional findExportedType(Luau::TypeChecker& typeChecker, const std::string& name) -{ - - if (typeChecker.globalScope->exportedTypeBindings.find(name) != typeChecker.globalScope->exportedTypeBindings.end()) - { - return typeChecker.globalScope->exportedTypeBindings.at(name); - } - return std::nullopt; -} - -Luau::TypeId makeInstanceType(Luau::TypeChecker& typeChecker, const SourceNode& node) +Luau::TypeId makeInstanceType(Luau::TypeArena& typeArena, const Luau::ScopePtr& globalScope, SourceNode& node) { std::optional baseType; if (node.className.has_value()) { - baseType = findExportedType(typeChecker, node.className.value()); + baseType = globalScope->lookupType(node.className.value()); } if (!baseType.has_value()) { - baseType = findExportedType(typeChecker, "Instance"); + baseType = globalScope->lookupType("Instance"); } LUAU_ASSERT(baseType); // TODO: is this ensured?? auto typeId = baseType.value().type; @@ -347,14 +346,14 @@ Luau::TypeId makeInstanceType(Luau::TypeChecker& typeChecker, const SourceNode& if (node.children.size() > 0) { // Add the children - Luau::TableTypeVar children{Luau::TableState::Sealed, typeChecker.globalScope->level}; + Luau::TableTypeVar children{Luau::TableState::Sealed, globalScope->level}; for (const auto& child : node.children) { - auto childProperty = Luau::makeProperty(makeInstanceType(typeChecker, *child.second), "@luau/instance"); + auto childProperty = Luau::makeProperty(makeInstanceType(typeArena, globalScope, *child.second), "@luau/instance"); children.props[child.first] = childProperty; } - Luau::TypeId childId = typeChecker.globalTypes.addType(children); - typeId = Luau::makeIntersection(typeChecker.globalTypes, {typeId, childId}); + Luau::TypeId childId = typeArena.addType(children); + typeId = Luau::makeIntersection(typeArena, {typeId, childId}); } return typeId; } @@ -433,7 +432,6 @@ int main(int argc, char** argv) CliConfigResolver configResolver; Luau::Frontend frontend(&fileResolver, &configResolver, frontendOptions); - Luau::registerBuiltinTypes(frontend.typeChecker); // If global definitions have been provided, then also register them @@ -465,7 +463,7 @@ int main(int argc, char** argv) { for (const auto& services : root.children) { - auto serviceType = findExportedType(frontend.typeChecker, services.first); + auto serviceType = frontend.typeChecker.globalScope->lookupType(services.first); if (serviceType.has_value()) { if (Luau::ClassTypeVar* ctv = Luau::getMutable(serviceType.value().type)) @@ -473,8 +471,9 @@ int main(int argc, char** argv) // Extend the props to include the children for (const auto& child : (*services.second).children) { - ctv->props[child.first] = - makeProperty(makeInstanceType(frontend.typeChecker, *(child.second)), "@luau/serviceChild"); + ctv->props[child.first] = makeProperty( + makeInstanceType(frontend.typeChecker.globalTypes, frontend.typeChecker.globalScope, *(child.second)), + "@luau/serviceChild"); } } } @@ -484,6 +483,29 @@ int main(int argc, char** argv) } } + auto moduleResolver = frontend.moduleResolver; + + frontend.typeChecker.prepareModuleScope = [&moduleResolver, fileResolver, stdinFilepath]( + const Luau::ModuleName& name, const Luau::ScopePtr& scope) + { + auto virtualPath = getCurrentModuleVirtualPath(name, fileResolver.sourceMap, stdinFilepath); + if (!virtualPath.has_value()) + return; + + auto node = RojoResolver::resolveRequireToSourceNode(virtualPath.value(), fileResolver.sourceMap.root); + if (!node.has_value()) + return; + + // HACK: we need a way to get the typeArena for the module, but I don't know how + // we can see that moduleScope->returnType is assigned before prepareModuleScope is called in TypeInfer, so we could try it this way... + LUAU_ASSERT(scope->returnType); + auto typeArena = scope->returnType->owningArena; + LUAU_ASSERT(typeArena); + auto ty = makeInstanceType(*typeArena, scope, node.value()); + + scope->bindings[Luau::AstName("script")] = Luau::Binding{ty, Luau::Location{}, {}, {}, std::nullopt}; + }; + Luau::freeze(frontend.typeChecker.globalTypes); std::vector files = getSourceFiles(argc, argv);