Commit b2ff10c4 authored by neis's avatar neis Committed by Commit bot

[modules] Detect all indirect exports and represent them as such.

BUG=v8:1569

Review-Url: https://codereview.chromium.org/2223893004
Cr-Commit-Position: refs/heads/master@{#38538}
parent 555c9619
......@@ -80,9 +80,26 @@ void ModuleDescriptor::AddStarExport(
exports_.Add(entry, zone);
}
void ModuleDescriptor::MakeIndirectExportsExplicit() {
for (auto entry : exports_) {
if (entry->export_name == nullptr) continue;
if (entry->import_name != nullptr) continue;
DCHECK_NOT_NULL(entry->local_name);
auto it = regular_imports_.find(entry->local_name);
if (it != regular_imports_.end()) {
// Found an indirect export.
DCHECK_NOT_NULL(it->second->module_request);
DCHECK_NOT_NULL(it->second->import_name);
entry->import_name = it->second->import_name;
entry->module_request = it->second->module_request;
entry->local_name = nullptr;
}
}
}
bool ModuleDescriptor::Validate(DeclarationScope* module_scope,
PendingCompilationErrorHandler* error_handler,
Zone* zone) const {
Zone* zone) {
DCHECK(module_scope->is_module_scope());
DCHECK_EQ(this, module_scope->module());
DCHECK_NOT_NULL(error_handler);
......@@ -120,6 +137,7 @@ bool ModuleDescriptor::Validate(DeclarationScope* module_scope,
}
}
MakeIndirectExportsExplicit();
return true;
}
......
......@@ -63,9 +63,9 @@ class ModuleDescriptor : public ZoneObject {
Zone* zone);
// Check if module is well-formed and report error if not.
// Also canonicalize indirect exports.
bool Validate(DeclarationScope* module_scope,
PendingCompilationErrorHandler* error_handler,
Zone* zone) const;
PendingCompilationErrorHandler* error_handler, Zone* zone);
struct ModuleEntry : public ZoneObject {
const Scanner::Location location;
......@@ -82,7 +82,7 @@ class ModuleDescriptor : public ZoneObject {
module_request(nullptr) {}
};
const ZoneList<const ModuleEntry*>& exports() const { return exports_; }
const ZoneList<ModuleEntry*>& exports() const { return exports_; }
// Empty imports and namespace imports.
const ZoneList<const ModuleEntry*>& special_imports() const {
......@@ -96,9 +96,27 @@ class ModuleDescriptor : public ZoneObject {
}
private:
ZoneList<const ModuleEntry*> exports_;
ZoneList<ModuleEntry*> exports_;
ZoneList<const ModuleEntry*> special_imports_;
ZoneMap<const AstRawString*, const ModuleEntry*> regular_imports_;
// Find any implicitly indirect exports and make them explicit.
//
// An explicitly indirect export is an export entry arising from an export
// statement of the following form:
// export {a as c} from "X";
// An implicitly indirect export corresponds to
// export {b as c};
// in the presence of an import statement of the form
// import {a as b} from "X";
// This function finds such implicitly indirect export entries and rewrites
// them by filling in the import name and module request, as well as nulling
// out the local name. Effectively, it turns
// import {a as b} from "X"; export {b as c};
// into:
// import {a as b} from "X"; export {a as c} from "X";
// (The import entry is never deleted.)
void MakeIndirectExportsExplicit();
};
} // namespace internal
......
......@@ -5588,6 +5588,13 @@ TEST(BasicImportExportParsing) {
"import { yield as y } from 'm.js';",
"import { static as s } from 'm.js';",
"import { let as l } from 'm.js';",
"import thing from 'a.js'; export {thing};",
"export {thing}; import thing from 'a.js';",
"import {thing} from 'a.js'; export {thing};",
"export {thing}; import {thing} from 'a.js';",
"import * as thing from 'a.js'; export {thing};",
"export {thing}; import * as thing from 'a.js';",
};
// clang-format on
......@@ -5911,6 +5918,32 @@ TEST(EnumReserved) {
RunModuleParserSyncTest(context_data, kErrorSources, kError);
}
static void CheckModuleEntry(const i::ModuleDescriptor::ModuleEntry* entry,
const char* export_name, const char* local_name, const char* import_name,
const char* module_request) {
CHECK_NOT_NULL(entry);
if (export_name == nullptr) {
CHECK_NULL(entry->export_name);
} else {
entry->export_name->IsOneByteEqualTo(export_name);
}
if (local_name == nullptr) {
CHECK_NULL(entry->local_name);
} else {
entry->local_name->IsOneByteEqualTo(local_name);
}
if (import_name == nullptr) {
CHECK_NULL(entry->import_name);
} else {
entry->import_name->IsOneByteEqualTo(import_name);
}
if (module_request == nullptr) {
CHECK_NULL(entry->module_request);
} else {
entry->module_request->IsOneByteEqualTo(module_request);
}
}
TEST(ModuleParsingInternals) {
i::Isolate* isolate = CcTest::i_isolate();
i::Factory* factory = isolate->factory();
......@@ -6040,125 +6073,51 @@ TEST(ModuleParsingInternals) {
CHECK_NOT_NULL(descriptor);
CHECK_EQ(11, descriptor->exports().length());
CHECK(descriptor->exports().at(0)->export_name->IsOneByteEqualTo("y"));
CHECK(descriptor->exports().at(0)->local_name->IsOneByteEqualTo("x"));
CHECK_NULL(descriptor->exports().at(0)->module_request);
CHECK_NULL(descriptor->exports().at(0)->import_name);
CHECK(descriptor->exports().at(1)->export_name->IsOneByteEqualTo("b"));
CHECK(descriptor->exports().at(1)->import_name->IsOneByteEqualTo("a"));
CHECK(descriptor->exports().at(1)->module_request->IsOneByteEqualTo("m.js"));
CHECK_NULL(descriptor->exports().at(1)->local_name);
CHECK(descriptor->exports().at(2)->module_request->IsOneByteEqualTo("p.js"));
CHECK_NULL(descriptor->exports().at(2)->local_name);
CHECK_NULL(descriptor->exports().at(2)->import_name);
CHECK_NULL(descriptor->exports().at(2)->export_name);
CHECK(descriptor->exports().at(3)->export_name->IsOneByteEqualTo("foo"));
CHECK(descriptor->exports().at(3)->local_name->IsOneByteEqualTo("foo"));
CHECK_NULL(descriptor->exports().at(3)->module_request);
CHECK_NULL(descriptor->exports().at(3)->import_name);
CHECK(descriptor->exports().at(4)->export_name->IsOneByteEqualTo("goo"));
CHECK(descriptor->exports().at(4)->local_name->IsOneByteEqualTo("goo"));
CHECK_NULL(descriptor->exports().at(4)->module_request);
CHECK_NULL(descriptor->exports().at(4)->import_name);
CHECK(descriptor->exports().at(5)->export_name->IsOneByteEqualTo("hoo"));
CHECK(descriptor->exports().at(5)->local_name->IsOneByteEqualTo("hoo"));
CHECK_NULL(descriptor->exports().at(5)->module_request);
CHECK_NULL(descriptor->exports().at(5)->import_name);
CHECK(descriptor->exports().at(6)->export_name->IsOneByteEqualTo("joo"));
CHECK(descriptor->exports().at(6)->local_name->IsOneByteEqualTo("joo"));
CHECK_NULL(descriptor->exports().at(6)->module_request);
CHECK_NULL(descriptor->exports().at(6)->import_name);
CHECK(descriptor->exports().at(7)->export_name->IsOneByteEqualTo("default"));
CHECK(descriptor->exports().at(7)->local_name->IsOneByteEqualTo("*default*"));
CHECK_NULL(descriptor->exports().at(7)->module_request);
CHECK_NULL(descriptor->exports().at(7)->import_name);
CHECK(descriptor->exports().at(8)->export_name->IsOneByteEqualTo("bb"));
CHECK(descriptor->exports().at(8)->local_name->IsOneByteEqualTo("aa"));
CHECK_NULL(descriptor->exports().at(8)->module_request);
CHECK_NULL(descriptor->exports().at(8)->import_name);
CHECK(descriptor->exports().at(9)->export_name->IsOneByteEqualTo("x"));
CHECK(descriptor->exports().at(9)->local_name->IsOneByteEqualTo("x"));
CHECK_NULL(descriptor->exports().at(9)->module_request);
CHECK_NULL(descriptor->exports().at(9)->import_name);
CHECK(descriptor->exports().at(10)->export_name->IsOneByteEqualTo("foob"));
CHECK(descriptor->exports().at(10)->local_name->IsOneByteEqualTo("foob"));
CHECK_NULL(descriptor->exports().at(10)->module_request);
CHECK_NULL(descriptor->exports().at(10)->import_name);
CheckModuleEntry(
descriptor->exports().at(0), "y", "x", nullptr, nullptr);
CheckModuleEntry(
descriptor->exports().at(1), "b", nullptr, "a", "m.js");
CheckModuleEntry(
descriptor->exports().at(2), nullptr, nullptr, nullptr, "p.js");
CheckModuleEntry(
descriptor->exports().at(3), "foo", "foo", nullptr, nullptr);
CheckModuleEntry(
descriptor->exports().at(4), "goo", "goo", nullptr, nullptr);
CheckModuleEntry(
descriptor->exports().at(5), "hoo", "hoo", nullptr, nullptr);
CheckModuleEntry(
descriptor->exports().at(6), "joo", "joo", nullptr, nullptr);
CheckModuleEntry(
descriptor->exports().at(7), "default", "*default*", nullptr, nullptr);
CheckModuleEntry(
descriptor->exports().at(8), "bb", nullptr, "aa", "m.js"); // !!!
CheckModuleEntry(
descriptor->exports().at(9), "x", "x", nullptr, nullptr);
CheckModuleEntry(
descriptor->exports().at(10), "foob", "foob", nullptr, nullptr);
CHECK_EQ(3, descriptor->special_imports().length());
CHECK_NULL(descriptor->special_imports().at(0)->local_name);
CHECK_NULL(descriptor->special_imports().at(0)->export_name);
CHECK_NULL(descriptor->special_imports().at(0)->import_name);
CHECK(descriptor->special_imports().at(0)->module_request->IsOneByteEqualTo(
"q.js"));
CHECK(
descriptor->special_imports().at(1)->local_name->IsOneByteEqualTo("loo"));
CHECK_NULL(descriptor->special_imports().at(1)->export_name);
CHECK_NULL(descriptor->special_imports().at(1)->import_name);
CHECK(descriptor->special_imports().at(1)->module_request->IsOneByteEqualTo(
"bar.js"));
CHECK(descriptor->special_imports().at(2)->local_name->IsOneByteEqualTo(
"foob"));
CHECK_NULL(descriptor->special_imports().at(2)->export_name);
CHECK_NULL(descriptor->special_imports().at(2)->import_name);
CHECK(descriptor->special_imports().at(2)->module_request->IsOneByteEqualTo(
"bar.js"));
CheckModuleEntry(
descriptor->special_imports().at(0), nullptr, nullptr, nullptr, "q.js");
CheckModuleEntry(
descriptor->special_imports().at(1), nullptr, "loo", nullptr, "bar.js");
CheckModuleEntry(
descriptor->special_imports().at(2), nullptr, "foob", nullptr, "bar.js");
CHECK_EQ(4, descriptor->regular_imports().size());
CHECK_NULL(descriptor->regular_imports()
.find(declarations->at(1)->proxy()->raw_name())
->second->export_name);
CHECK(descriptor->regular_imports()
.find(declarations->at(1)->proxy()->raw_name())
->second->import_name->IsOneByteEqualTo("q"));
CHECK(descriptor->regular_imports()
.find(declarations->at(1)->proxy()->raw_name())
->second->module_request->IsOneByteEqualTo("m.js"));
CHECK_NULL(descriptor->regular_imports()
.find(declarations->at(2)->proxy()->raw_name())
->second->export_name);
CHECK(descriptor->regular_imports()
.find(declarations->at(2)->proxy()->raw_name())
->second->import_name->IsOneByteEqualTo("default"));
CHECK(descriptor->regular_imports()
.find(declarations->at(2)->proxy()->raw_name())
->second->module_request->IsOneByteEqualTo("n.js"));
CHECK_NULL(descriptor->regular_imports()
.find(declarations->at(9)->proxy()->raw_name())
->second->export_name);
CHECK(descriptor->regular_imports()
.find(declarations->at(9)->proxy()->raw_name())
->second->import_name->IsOneByteEqualTo("m"));
CHECK(descriptor->regular_imports()
.find(declarations->at(9)->proxy()->raw_name())
->second->module_request->IsOneByteEqualTo("m.js"));
CHECK_NULL(descriptor->regular_imports()
.find(declarations->at(10)->proxy()->raw_name())
->second->export_name);
CHECK(descriptor->regular_imports()
.find(declarations->at(10)->proxy()->raw_name())
->second->import_name->IsOneByteEqualTo("aa"));
CHECK(descriptor->regular_imports()
.find(declarations->at(10)->proxy()->raw_name())
->second->module_request->IsOneByteEqualTo("m.js"));
const i::ModuleDescriptor::ModuleEntry* entry;
entry = descriptor->regular_imports().find(
declarations->at(1)->proxy()->raw_name())->second;
CheckModuleEntry(entry, nullptr, "z", "q", "m.js");
entry = descriptor->regular_imports().find(
declarations->at(2)->proxy()->raw_name())->second;
CheckModuleEntry(entry, nullptr, "n", "default", "n.js");
entry = descriptor->regular_imports().find(
declarations->at(9)->proxy()->raw_name())->second;
CheckModuleEntry(entry, nullptr, "mm", "m", "m.js");
entry = descriptor->regular_imports().find(
declarations->at(10)->proxy()->raw_name())->second;
CheckModuleEntry(entry, nullptr, "aa", "aa", "m.js");
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment