Bug 1484948 - Parse dynamic module import syntax but throw SyntaxError if used r=jorendorff
authorJon Coppeard <jcoppeard@mozilla.com>
Fri, 07 Sep 2018 17:52:49 +0100
changeset 490964 d1b2141b1c454f28b8d35164c958e9ddcc7058fe
parent 490963 293c4672dd15110112e96e277a30e3180133278d
child 490965 3026c40acec365f6606c39234bba5f4e99c83dac
child 491001 c3dab9cc38fe6f171fe6e16dcf3f83f296b3737d
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1484948
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1484948 - Parse dynamic module import syntax but throw SyntaxError if used r=jorendorff
js/src/builtin/ReflectParse.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/FoldConstants.cpp
js/src/frontend/FullParseHandler.h
js/src/frontend/NameFunctions.cpp
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/frontend/SyntaxParseHandler.h
js/src/jit-test/tests/modules/dynamic-import-expression.js
js/src/js.msg
js/src/jsast.tbl
testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-fetch-error.sub.html.ini
testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html.ini
testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports.html.ini
testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-classic.html.ini
testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-module.html.ini
testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-classic.html.ini
testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-module.html.ini
--- a/js/src/builtin/ReflectParse.cpp
+++ b/js/src/builtin/ReflectParse.cpp
@@ -594,16 +594,19 @@ class NodeBuilder
     MOZ_MUST_USE bool thisExpression(TokenPos* pos, MutableHandleValue dst);
 
     MOZ_MUST_USE bool yieldExpression(HandleValue arg, YieldKind kind, TokenPos* pos,
                                       MutableHandleValue dst);
 
     MOZ_MUST_USE bool metaProperty(HandleValue meta, HandleValue property, TokenPos* pos,
                                    MutableHandleValue dst);
 
+    MOZ_MUST_USE bool callImportExpression(HandleValue ident, HandleValue arg, TokenPos* pos,
+                                           MutableHandleValue dst);
+
     MOZ_MUST_USE bool super(TokenPos* pos, MutableHandleValue dst);
 
     /*
      * declarations
      */
 
     MOZ_MUST_USE bool variableDeclaration(NodeVector& elts, VarDeclKind kind, TokenPos* pos,
                                           MutableHandleValue dst);
@@ -1595,16 +1598,30 @@ NodeBuilder::metaProperty(HandleValue me
 
     return newNode(AST_METAPROPERTY, pos,
                    "meta", meta,
                    "property", property,
                    dst);
 }
 
 bool
+NodeBuilder::callImportExpression(HandleValue ident, HandleValue arg, TokenPos* pos,
+                                  MutableHandleValue dst)
+{
+    RootedValue cb(cx, callbacks[AST_CALL_IMPORT]);
+    if (!cb.isNull())
+        return callback(cb, arg, pos, dst);
+
+    return newNode(AST_CALL_IMPORT, pos,
+                   "ident", ident,
+                   "arg", arg,
+                   dst);
+}
+
+bool
 NodeBuilder::super(TokenPos* pos, MutableHandleValue dst)
 {
     RootedValue cb(cx, callbacks[AST_SUPER]);
     if (!cb.isNull())
         return callback(cb, pos, dst);
 
     return newNode(AST_SUPER, pos, dst);
 }
@@ -2945,16 +2962,31 @@ ASTSerializer::expression(ParseNode* pn,
             secondStr = cx->names().meta;
         }
 
         return identifier(firstStr, &pn->pn_left->pn_pos, &firstIdent) &&
                identifier(secondStr, &pn->pn_right->pn_pos, &secondIdent) &&
                builder.metaProperty(firstIdent, secondIdent, &pn->pn_pos, dst);
       }
 
+      case ParseNodeKind::CallImport:
+      {
+        MOZ_ASSERT(pn->pn_left->isKind(ParseNodeKind::PosHolder));
+        MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
+        MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
+
+        RootedValue ident(cx);
+        RootedValue arg(cx);
+
+        HandlePropertyName name = cx->names().import;
+        return identifier(name, &pn->pn_left->pn_pos, &ident) &&
+               expression(pn->pn_right, &arg) &&
+               builder.callImportExpression(ident, arg, &pn->pn_pos, dst);
+      }
+
       case ParseNodeKind::SetThis:
         // SETTHIS is used to assign the result of a super() call to |this|.
         // It's not part of the original AST, so just forward to the call.
         MOZ_ASSERT(pn->pn_left->isKind(ParseNodeKind::Name));
         return expression(pn->pn_right, dst);
 
       default:
         LOCAL_NOT_REACHED("unexpected expression type");
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -1212,16 +1212,21 @@ BytecodeEmitter::checkSideEffects(ParseN
         return true;
 
       // Likewise.
       case ParseNodeKind::Export:
         MOZ_ASSERT(pn->isArity(PN_UNARY));
         *answer = true;
         return true;
 
+      case ParseNodeKind::CallImport:
+        MOZ_ASSERT(pn->isArity(PN_BINARY));
+        *answer = true;
+        return true;
+
       // Every part of a loop might be effect-free, but looping infinitely *is*
       // an effect.  (Language lawyer trivia: C++ says threads can be assumed
       // to exit or have side effects, C++14 [intro.multithread]p27, so a C++
       // implementation's equivalent of the below could set |*answer = false;|
       // if all loop sub-nodes set |*answer = false|!)
       case ParseNodeKind::DoWhile:
       case ParseNodeKind::While:
       case ParseNodeKind::For:
@@ -8303,16 +8308,20 @@ BytecodeEmitter::emitTree(ParseNode* pn,
             return false;
         break;
 
       case ParseNodeKind::ImportMeta:
         if (!emit1(JSOP_IMPORTMETA))
             return false;
         break;
 
+      case ParseNodeKind::CallImport:
+        reportError(nullptr, JSMSG_NO_DYNAMIC_IMPORT);
+        return false;
+
       case ParseNodeKind::SetThis:
         if (!emitSetThis(pn))
             return false;
         break;
 
       case ParseNodeKind::PropertyName:
       case ParseNodeKind::PosHolder:
         MOZ_FALLTHROUGH_ASSERT("Should never try to emit ParseNodeKind::PosHolder or ::Property");
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -131,16 +131,17 @@ ContainsHoistedDeclaration(JSContext* cx
       case ParseNodeKind::ImportSpecList:
       case ParseNodeKind::ImportSpec:
       case ParseNodeKind::ExportFrom:
       case ParseNodeKind::ExportDefault:
       case ParseNodeKind::ExportSpecList:
       case ParseNodeKind::ExportSpec:
       case ParseNodeKind::Export:
       case ParseNodeKind::ExportBatchSpec:
+      case ParseNodeKind::CallImport:
         *result = false;
         return true;
 
       // Statements possibly containing hoistable declarations only in the left
       // half, in ParseNode terms -- the loop body in AST terms.
       case ParseNodeKind::DoWhile:
         return ContainsHoistedDeclaration(cx, node->pn_left, result);
 
@@ -1750,16 +1751,21 @@ Fold(JSContext* cx, ParseNode** pnp, Per
 
       case ParseNodeKind::NewTarget:
       case ParseNodeKind::ImportMeta:
         MOZ_ASSERT(pn->isArity(PN_BINARY));
         MOZ_ASSERT(pn->pn_left->isKind(ParseNodeKind::PosHolder));
         MOZ_ASSERT(pn->pn_right->isKind(ParseNodeKind::PosHolder));
         return true;
 
+      case ParseNodeKind::CallImport:
+        MOZ_ASSERT(pn->isArity(PN_BINARY));
+        MOZ_ASSERT(pn->pn_left->isKind(ParseNodeKind::PosHolder));
+        return Fold(cx, &pn->pn_right, parser);
+
       case ParseNodeKind::ClassNames:
         MOZ_ASSERT(pn->isArity(PN_BINARY));
         if (ParseNode*& outerBinding = pn->pn_left) {
             if (!Fold(cx, &outerBinding, parser))
                 return false;
         }
         return Fold(cx, &pn->pn_right, parser);
 
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -557,16 +557,20 @@ class FullParseHandler
     ParseNode* newExportBatchSpec(const TokenPos& pos) {
         return new_<NullaryNode>(ParseNodeKind::ExportBatchSpec, JSOP_NOP, pos);
     }
 
     ParseNode* newImportMeta(ParseNode* importHolder, ParseNode* metaHolder) {
         return new_<BinaryNode>(ParseNodeKind::ImportMeta, JSOP_NOP, importHolder, metaHolder);
     }
 
+    ParseNode* newCallImport(ParseNode* importHolder, ParseNode* singleArg) {
+        return new_<BinaryNode>(ParseNodeKind::CallImport, JSOP_NOP, importHolder, singleArg);
+    }
+
     ParseNode* newExprStatement(ParseNode* expr, uint32_t end) {
         MOZ_ASSERT(expr->pn_pos.end <= end);
         return new_<UnaryNode>(ParseNodeKind::ExpressionStatement,
                                TokenPos(expr->pn_pos.begin, end), expr);
     }
 
     ParseNode* newIfStatement(uint32_t begin, ParseNode* cond, ParseNode* thenBranch,
                               ParseNode* elseBranch)
--- a/js/src/frontend/NameFunctions.cpp
+++ b/js/src/frontend/NameFunctions.cpp
@@ -781,16 +781,22 @@ class NameResolver
                 MOZ_ASSERT(!item->pn_left->expr());
                 MOZ_ASSERT(item->pn_right->isKind(ParseNodeKind::Name));
                 MOZ_ASSERT(!item->pn_right->expr());
             }
 #endif
             break;
           }
 
+          case ParseNodeKind::CallImport:
+            MOZ_ASSERT(cur->isArity(PN_BINARY));
+            if (!resolve(cur->pn_right, prefix))
+                return false;
+            break;
+
           case ParseNodeKind::Dot:
             MOZ_ASSERT(cur->isArity(PN_BINARY));
 
             // Super prop nodes do not have a meaningful LHS
             if (cur->as<PropertyAccess>().isSuper())
                 break;
             if (!resolve(cur->pn_left, prefix))
                 return false;
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -131,16 +131,17 @@ class ObjectBox;
     F(ClassMethodList) \
     F(ClassNames) \
     F(NewTarget) \
     F(PosHolder) \
     F(SuperBase) \
     F(SuperCall) \
     F(SetThis) \
     F(ImportMeta) \
+    F(CallImport) \
     \
     /* Unary operators. */ \
     F(TypeOfName) \
     F(TypeOfExpr) \
     F(Void) \
     F(Not) \
     F(BitNot) \
     F(Await) \
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -5437,25 +5437,25 @@ template <class ParseHandler, typename C
 inline typename ParseHandler::Node
 GeneralParser<ParseHandler, CharT>::importDeclaration()
 {
     return asFinalParser()->importDeclaration();
 }
 
 template <class ParseHandler, typename CharT>
 inline typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::importDeclarationOrImportMeta(YieldHandling yieldHandling)
+GeneralParser<ParseHandler, CharT>::importDeclarationOrImportExpr(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Import));
 
     TokenKind tt;
     if (!tokenStream.peekToken(&tt))
         return null();
 
-    if (tt == TokenKind::Dot)
+    if (tt == TokenKind::Dot || tt == TokenKind::LeftParen)
         return expressionStatement(yieldHandling);
 
     return importDeclaration();
 }
 
 template<typename CharT>
 bool
 Parser<FullParseHandler, CharT>::checkExportedName(JSAtom* exportName)
@@ -7806,17 +7806,17 @@ GeneralParser<ParseHandler, CharT>::stat
 
       // |class| is also forbidden by lookahead restriction.
       case TokenKind::Class:
         error(JSMSG_FORBIDDEN_AS_STATEMENT, "classes");
         return null();
 
       // ImportDeclaration (only inside modules)
       case TokenKind::Import:
-        return importDeclarationOrImportMeta(yieldHandling);
+        return importDeclarationOrImportExpr(yieldHandling);
 
       // ExportDeclaration (only inside modules)
       case TokenKind::Export:
         return exportDeclaration();
 
       // Miscellaneous error cases arguably better caught here than elsewhere.
 
       case TokenKind::Catch:
@@ -7999,17 +7999,17 @@ GeneralParser<ParseHandler, CharT>::stat
       //     LetOrConst BindingList[?In, ?Yield]
       case TokenKind::Const:
         // [In] is the default behavior, because for-loops specially parse
         // their heads to handle |in| in this situation.
         return lexicalDeclaration(yieldHandling, DeclarationKind::Const);
 
       // ImportDeclaration (only inside modules)
       case TokenKind::Import:
-        return importDeclarationOrImportMeta(yieldHandling);
+        return importDeclarationOrImportExpr(yieldHandling);
 
       // ExportDeclaration (only inside modules)
       case TokenKind::Export:
         return exportDeclaration();
 
       // Miscellaneous error cases arguably better caught here than elsewhere.
 
       case TokenKind::Catch:
@@ -8836,17 +8836,17 @@ GeneralParser<ParseHandler, CharT>::memb
     } else if (tt == TokenKind::Super) {
         Node thisName = newThisName();
         if (!thisName)
             return null();
         lhs = handler.newSuperBase(thisName, pos());
         if (!lhs)
             return null();
     } else if (tt == TokenKind::Import) {
-        lhs = importMeta();
+        lhs = importExpr(yieldHandling);
         if (!lhs)
             return null();
     } else {
         lhs = primaryExpr(yieldHandling, tripledotHandling, tt, possibleError, invoked);
         if (!lhs)
             return null();
     }
 
@@ -10019,51 +10019,58 @@ GeneralParser<ParseHandler, CharT>::tryN
         return false;
 
     newTarget = handler.newNewTarget(newHolder, targetHolder);
     return !!newTarget;
 }
 
 template <class ParseHandler, typename CharT>
 typename ParseHandler::Node
-GeneralParser<ParseHandler, CharT>::importMeta()
+GeneralParser<ParseHandler, CharT>::importExpr(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Import));
 
-    uint32_t begin = pos().begin;
-
-    if (parseGoal() != ParseGoal::Module) {
-        errorAt(begin, JSMSG_IMPORT_OUTSIDE_MODULE);
-        return null();
-    }
-
     Node importHolder = handler.newPosHolder(pos());
     if (!importHolder)
         return null();
 
     TokenKind next;
     if (!tokenStream.getToken(&next))
         return null();
-    if (next != TokenKind::Dot) {
-        error(JSMSG_UNEXPECTED_TOKEN, "dot", TokenKindToDesc(next));
-        return null();
-    }
-
-    if (!tokenStream.getToken(&next))
-        return null();
-    if (next != TokenKind::Meta) {
-        error(JSMSG_UNEXPECTED_TOKEN, "meta", TokenKindToDesc(next));
-        return null();
-    }
-
-    Node metaHolder = handler.newPosHolder(pos());
-    if (!metaHolder)
-        return null();
-
-    return handler.newImportMeta(importHolder, metaHolder);
+
+    if (next == TokenKind::Dot) {
+        if (!tokenStream.getToken(&next))
+            return null();
+        if (next != TokenKind::Meta) {
+            error(JSMSG_UNEXPECTED_TOKEN, "meta", TokenKindToDesc(next));
+            return null();
+        }
+
+        if (parseGoal() != ParseGoal::Module) {
+            errorAt(pos().begin, JSMSG_IMPORT_META_OUTSIDE_MODULE);
+            return null();
+        }
+
+        Node metaHolder = handler.newPosHolder(pos());
+        if (!metaHolder)
+            return null();
+
+        return handler.newImportMeta(importHolder, metaHolder);
+    } else if (next == TokenKind::LeftParen) {
+        Node arg = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
+        if (!arg)
+            return null();
+
+        MUST_MATCH_TOKEN_MOD(TokenKind::RightParen, TokenStream::Operand, JSMSG_PAREN_AFTER_ARGS);
+
+        return handler.newCallImport(importHolder, arg);
+    } else {
+        error(JSMSG_UNEXPECTED_TOKEN_NO_EXPECT, TokenKindToDesc(next));
+        return null();
+    }
 }
 
 template <class ParseHandler, typename CharT>
 typename ParseHandler::Node
 GeneralParser<ParseHandler, CharT>::primaryExpr(YieldHandling yieldHandling,
                                                 TripledotHandling tripledotHandling,
                                                 TokenKind tt, PossibleError* possibleError,
                                                 InvokedPrediction invoked /* = PredictUninvoked */)
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -1040,17 +1040,17 @@ class MOZ_STACK_CLASS GeneralParser
     Node labeledItem(YieldHandling yieldHandling);
 
     Node ifStatement(YieldHandling yieldHandling);
     Node consequentOrAlternative(YieldHandling yieldHandling);
 
     Node lexicalDeclaration(YieldHandling yieldHandling, DeclarationKind kind);
 
     inline Node importDeclaration();
-    Node importDeclarationOrImportMeta(YieldHandling yieldHandling);
+    Node importDeclarationOrImportExpr(YieldHandling yieldHandling);
 
     Node exportFrom(uint32_t begin, Node specList);
     Node exportBatch(uint32_t begin);
     inline bool checkLocalExportNames(Node node);
     Node exportClause(uint32_t begin);
     Node exportFunctionDeclaration(uint32_t begin, uint32_t toStringStart,
                                    FunctionAsyncKind asyncKind = FunctionAsyncKind::SyncFunction);
     Node exportVariableStatement(uint32_t begin);
@@ -1140,17 +1140,17 @@ class MOZ_STACK_CLASS GeneralParser
     Node primaryExpr(YieldHandling yieldHandling, TripledotHandling tripledotHandling,
                      TokenKind tt, PossibleError* possibleError,
                      InvokedPrediction invoked = PredictUninvoked);
     Node exprInParens(InHandling inHandling, YieldHandling yieldHandling,
                       TripledotHandling tripledotHandling, PossibleError* possibleError = nullptr);
 
     bool tryNewTarget(Node& newTarget);
 
-    Node importMeta();
+    Node importExpr(YieldHandling yieldHandling);
 
     Node methodDefinition(uint32_t toStringStart, PropertyType propType, HandleAtom funName);
 
     /*
      * Additional JS parsers.
      */
     bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind,
                            Node funcpn);
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -297,16 +297,19 @@ class SyntaxParseHandler
         return NodeGeneric;
     }
     Node newExportBatchSpec(const TokenPos& pos) {
         return NodeGeneric;
     }
     Node newImportMeta(Node importHolder, Node metaHolder) {
         return NodeGeneric;
     }
+    Node newCallImport(Node importHolder, Node singleArg) {
+        return NodeGeneric;
+    }
 
     Node newSetThis(Node thisName, Node value) { return value; }
 
     Node newExprStatement(Node expr, uint32_t end) {
         return expr == NodeUnparenthesizedString ? NodeStringExprStatement : NodeGeneric;
     }
 
     Node newIfStatement(uint32_t begin, Node cond, Node then, Node else_) { return NodeGeneric; }
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/modules/dynamic-import-expression.js
@@ -0,0 +1,85 @@
+load(libdir + "match.js");
+load(libdir + "asserts.js");
+
+var { Pattern, MatchError } = Match;
+
+program = (elts) => Pattern({
+    type: "Program",
+    body: elts
+});
+expressionStatement = (expression) => Pattern({
+    type: "ExpressionStatement",
+    expression: expression
+});
+assignmentExpression = (left, operator, right) => Pattern({
+    type: "AssignmentExpression",
+    operator: operator,
+    left: left,
+    right: right
+});
+ident = (name) => Pattern({
+    type: "Identifier",
+    name: name
+});
+importCall = (ident, singleArg) => Pattern({
+    type: "CallImport",
+    ident: ident,
+    arg: singleArg
+});
+
+function parseAsClassicScript(source)
+{
+    return Reflect.parse(source);
+}
+
+function parseAsModuleScript(source)
+{
+    return Reflect.parse(source, {target: "module"});
+}
+
+for (let parse of [parseAsModuleScript, parseAsClassicScript]) {
+    program([
+        expressionStatement(
+            importCall(
+                ident("import"),
+                ident("foo")
+            )
+        )
+    ]).assert(parse("import(foo);"));
+
+    program([
+        expressionStatement(
+            assignmentExpression(
+                ident("x"),
+                "=",
+                importCall(
+                    ident("import"),
+                    ident("foo")
+                )
+            )
+        )
+    ]).assert(parse("x = import(foo);"));
+}
+
+function assertParseThrowsSyntaxError(source)
+{
+    assertThrowsInstanceOf(() => parseAsClassicScript(source), SyntaxError);
+    assertThrowsInstanceOf(() => parseAsModuleScript(source), SyntaxError);
+}
+
+assertParseThrowsSyntaxError("import");
+assertParseThrowsSyntaxError("import(");
+assertParseThrowsSyntaxError("import(1,");
+assertParseThrowsSyntaxError("import(1, 2");
+assertParseThrowsSyntaxError("import(1, 2)");
+assertParseThrowsSyntaxError("x = import");
+assertParseThrowsSyntaxError("x = import(");
+assertParseThrowsSyntaxError("x = import(1,");
+assertParseThrowsSyntaxError("x = import(1, 2");
+assertParseThrowsSyntaxError("x = import(1, 2)");
+
+// import() is not implemented.
+assertThrowsInstanceOf(() => eval("import('foo')"),
+                       SyntaxError);
+assertThrowsInstanceOf(() => parseModule("import('foo')"),
+                       SyntaxError);
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -258,17 +258,17 @@ MSG_DEF(JSMSG_FINALLY_WITHOUT_TRY,     0
 MSG_DEF(JSMSG_FORBIDDEN_AS_STATEMENT,  1, JSEXN_SYNTAXERR, "{0} can't appear in single-statement context")
 MSG_DEF(JSMSG_FOR_AWAIT_OUTSIDE_ASYNC, 0, JSEXN_SYNTAXERR, "for await (... of ...) is only valid in async functions and async generators")
 MSG_DEF(JSMSG_FROM_AFTER_IMPORT_CLAUSE, 0, JSEXN_SYNTAXERR, "missing keyword 'from' after import clause")
 MSG_DEF(JSMSG_FROM_AFTER_EXPORT_STAR,  0, JSEXN_SYNTAXERR, "missing keyword 'from' after export *")
 MSG_DEF(JSMSG_GARBAGE_AFTER_INPUT,     2, JSEXN_SYNTAXERR, "unexpected garbage after {0}, starting with {1}")
 MSG_DEF(JSMSG_IDSTART_AFTER_NUMBER,    0, JSEXN_SYNTAXERR, "identifier starts immediately after numeric literal")
 MSG_DEF(JSMSG_BAD_ESCAPE,              0, JSEXN_SYNTAXERR, "invalid escape sequence")
 MSG_DEF(JSMSG_ILLEGAL_CHARACTER,       0, JSEXN_SYNTAXERR, "illegal character")
-MSG_DEF(JSMSG_IMPORT_OUTSIDE_MODULE,   0, JSEXN_SYNTAXERR, "the import keyword may only appear in a module")
+MSG_DEF(JSMSG_IMPORT_META_OUTSIDE_MODULE, 0, JSEXN_SYNTAXERR, "import.meta may only appear in a module")
 MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 0, JSEXN_SYNTAXERR, "import declarations may only appear at top level of a module")
 MSG_DEF(JSMSG_OF_AFTER_FOR_LOOP_DECL,  0, JSEXN_SYNTAXERR, "a declaration in the head of a for-of loop can't have an initializer")
 MSG_DEF(JSMSG_IN_AFTER_LEXICAL_FOR_DECL,0,JSEXN_SYNTAXERR, "a lexical declaration in the head of a for-in loop can't have an initializer")
 MSG_DEF(JSMSG_INVALID_FOR_IN_DECL_WITH_INIT,0,JSEXN_SYNTAXERR,"for-in loop head declarations may not have initializers")
 MSG_DEF(JSMSG_INVALID_ID,              1, JSEXN_SYNTAXERR, "{0} is an invalid identifier")
 MSG_DEF(JSMSG_LABEL_NOT_FOUND,         0, JSEXN_SYNTAXERR, "label not found")
 MSG_DEF(JSMSG_LEXICAL_DECL_NOT_IN_BLOCK,   1, JSEXN_SYNTAXERR, "{0} declaration not directly within block")
 MSG_DEF(JSMSG_LEXICAL_DECL_LABEL,      1, JSEXN_SYNTAXERR, "{0} declarations cannot be labelled")
@@ -601,16 +601,17 @@ MSG_DEF(JSMSG_REINIT_THIS,       0, JSEX
 MSG_DEF(JSMSG_BAD_DEFAULT_EXPORT,        0, JSEXN_SYNTAXERR, "default export cannot be provided by export *")
 MSG_DEF(JSMSG_MISSING_INDIRECT_EXPORT,   0, JSEXN_SYNTAXERR, "indirect export not found")
 MSG_DEF(JSMSG_AMBIGUOUS_INDIRECT_EXPORT, 0, JSEXN_SYNTAXERR, "ambiguous indirect export")
 MSG_DEF(JSMSG_MISSING_IMPORT,            0, JSEXN_SYNTAXERR, "import not found")
 MSG_DEF(JSMSG_AMBIGUOUS_IMPORT,          0, JSEXN_SYNTAXERR, "ambiguous import")
 MSG_DEF(JSMSG_MISSING_NAMESPACE_EXPORT,  0, JSEXN_SYNTAXERR, "export not found for namespace")
 MSG_DEF(JSMSG_MISSING_EXPORT,            1, JSEXN_SYNTAXERR, "local binding for export '{0}' not found")
 MSG_DEF(JSMSG_BAD_MODULE_STATUS,         0, JSEXN_INTERNALERR, "module record has unexpected status")
+MSG_DEF(JSMSG_NO_DYNAMIC_IMPORT,         0, JSEXN_SYNTAXERR, "dynamic module import is not implemented")
 
 // Promise
 MSG_DEF(JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF,       0, JSEXN_TYPEERR, "A promise cannot be resolved with itself.")
 MSG_DEF(JSMSG_PROMISE_CAPABILITY_HAS_SOMETHING_ALREADY, 0, JSEXN_TYPEERR, "GetCapabilitiesExecutor function already invoked with non-undefined values.")
 MSG_DEF(JSMSG_PROMISE_RESOLVE_FUNCTION_NOT_CALLABLE,    0, JSEXN_TYPEERR, "A Promise subclass passed a non-callable value as the resolve function.")
 MSG_DEF(JSMSG_PROMISE_REJECT_FUNCTION_NOT_CALLABLE,     0, JSEXN_TYPEERR, "A Promise subclass passed a non-callable value as the reject function.")
 MSG_DEF(JSMSG_PROMISE_ERROR_IN_WRAPPED_REJECTION_REASON,0, JSEXN_INTERNALERR, "Promise rejection value is a non-unwrappable cross-compartment wrapper.")
 
--- a/js/src/jsast.tbl
+++ b/js/src/jsast.tbl
@@ -33,16 +33,17 @@ ASTDEF(AST_ARROW_EXPR,            "Arrow
 ASTDEF(AST_ARRAY_EXPR,            "ArrayExpression",                "arrayExpression")
 ASTDEF(AST_SPREAD_EXPR,           "SpreadExpression",               "spreadExpression")
 ASTDEF(AST_OBJECT_EXPR,           "ObjectExpression",               "objectExpression")
 ASTDEF(AST_THIS_EXPR,             "ThisExpression",                 "thisExpression")
 ASTDEF(AST_YIELD_EXPR,            "YieldExpression",                "yieldExpression")
 ASTDEF(AST_CLASS_EXPR,            "ClassExpression",                "classExpression")
 ASTDEF(AST_METAPROPERTY,          "MetaProperty",                   "metaProperty")
 ASTDEF(AST_SUPER,                 "Super",                          "super")
+ASTDEF(AST_CALL_IMPORT,           "CallImport",                     "callImport")
 
 ASTDEF(AST_EMPTY_STMT,            "EmptyStatement",                 "emptyStatement")
 ASTDEF(AST_BLOCK_STMT,            "BlockStatement",                 "blockStatement")
 ASTDEF(AST_EXPR_STMT,             "ExpressionStatement",            "expressionStatement")
 ASTDEF(AST_LAB_STMT,              "LabeledStatement",               "labeledStatement")
 ASTDEF(AST_IF_STMT,               "IfStatement",                    "ifStatement")
 ASTDEF(AST_SWITCH_STMT,           "SwitchStatement",                "switchStatement")
 ASTDEF(AST_WHILE_STMT,            "WhileStatement",                 "whileStatement")
--- a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-fetch-error.sub.html.ini
+++ b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-fetch-error.sub.html.ini
@@ -1,4 +1,8 @@
 [dynamic-imports-fetch-error.sub.html]
+  expected: ERROR
   [import(): error cases occuring during fetching]
     expected: FAIL
 
+  [import() must reject when there is a wrong MIME type]
+    expected: FAIL
+
--- a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html.ini
+++ b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html.ini
@@ -1,4 +1,8 @@
 [dynamic-imports-script-error.html]
+  expected: ERROR
   [import(): error cases caused by the imported module script]
     expected: FAIL
 
+  [import() must reject when there is a parse error]
+    expected: FAIL
+
--- a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports.html.ini
+++ b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports.html.ini
@@ -1,4 +1,7 @@
 [dynamic-imports.html]
   [Basic dynamic imports]
     expected: FAIL
 
+  [Dynamic imports should resolve module.]
+    expected: FAIL
+
--- a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-classic.html.ini
+++ b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-classic.html.ini
@@ -1,7 +1,10 @@
 [propagate-nonce-external-classic.html]
   [Untitled]
     expected: FAIL
 
   [propagate-nonce-external-classic]
     expected: FAIL
 
+  [Dynamically imported module should eval when imported from script w/ a valid nonce.]
+    expected: FAIL
+
--- a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-module.html.ini
+++ b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-module.html.ini
@@ -1,7 +1,10 @@
 [propagate-nonce-external-module.html]
   [Untitled]
     expected: FAIL
 
   [propagate-nonce-external-module]
     expected: FAIL
 
+  [Dynamically imported module should eval when imported from script w/ a valid nonce.]
+    expected: FAIL
+
--- a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-classic.html.ini
+++ b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-classic.html.ini
@@ -1,7 +1,10 @@
 [propagate-nonce-inline-classic.html]
   [Untitled]
     expected: FAIL
 
   [propagate-nonce-inline-classic]
     expected: FAIL
 
+  [Dynamically imported module should eval when imported from script w/ a valid nonce.]
+    expected: FAIL
+
--- a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-module.html.ini
+++ b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-module.html.ini
@@ -1,7 +1,10 @@
 [propagate-nonce-inline-module.html]
   [Untitled]
     expected: FAIL
 
   [propagate-nonce-inline-module]
     expected: FAIL
 
+  [Dynamically imported module should eval when imported from script w/ a valid nonce.]
+    expected: FAIL
+