Bug 1585234 - Part 1: Remove unnecessary Variant wrap/match on context. r=Yoric
authorTooru Fujisawa <arai_a@mac.com>
Mon, 07 Oct 2019 05:10:32 +0000
changeset 496475 a384b2a67709945e40216aa08f4a4afbcd9a3b12
parent 496474 e62a594ec4d2b8e16e1c37bde68a3605bacb7e99
child 496476 8f3223ff55e267cb478968433c8f1cfa4e4fcb97
push id97270
push userarai_a@mac.com
push dateMon, 07 Oct 2019 05:16:21 +0000
treeherderautoland@b7dd0f12d98b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersYoric
bugs1585234
milestone71.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 1585234 - Part 1: Remove unnecessary Variant wrap/match on context. r=Yoric A half of Parser methods are using single context type, and remaining are using 2 context types. There are no place that uses 3 context types necessarily. Part 1 modifies the code generator to collect context type information, and reflect the information to Parser methods, to use single non-Variant type if possible. Also changed corresponding TokenReader methods to use single non-Variant type. Differential Revision: https://phabricator.services.mozilla.com/D48011
js/src/frontend/BinAST.yaml
js/src/frontend/BinASTParser.cpp
js/src/frontend/BinASTParser.h
js/src/frontend/BinASTParserPerTokenizer.cpp
js/src/frontend/BinASTTokenReaderContext.cpp
js/src/frontend/BinASTTokenReaderContext.h
js/src/frontend/BinASTTokenReaderMultipart.cpp
js/src/frontend/BinASTTokenReaderMultipart.h
js/src/frontend/binast/src/main.rs
--- a/js/src/frontend/BinAST.yaml
+++ b/js/src/frontend/BinAST.yaml
@@ -654,17 +654,17 @@ Block:
     BINJS_TRY_DECL(result, handler_.newLexicalScope(*bindings, statements));
 
 BreakStatement:
   fields:
     label:
       block:
         replace: |
           RootedAtom label(cx_);
-          MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom(Context(FieldContext(BinASTInterfaceAndField::BreakStatement__Label))));
+          MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom(FieldContext(BinASTInterfaceAndField::BreakStatement__Label)));
 
   build: |
     if (label) {
       if (!IsIdentifier(label)) {
         return raiseError("Invalid identifier");
       }
     }
 
@@ -798,17 +798,17 @@ ConditionalExpression:
                    handler_.newConditional(test, consequent, alternate));
 
 ContinueStatement:
   fields:
     label:
       block:
         replace: |
           RootedAtom label(cx_);
-          MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom(Context(FieldContext(BinASTInterfaceAndField::ContinueStatement__Label))));
+          MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom(FieldContext(BinASTInterfaceAndField::ContinueStatement__Label)));
 
   build: |
     if (label) {
       if (!IsIdentifier(label)) {
         return raiseError("ContinueStatement - Label MUST be an identifier");
       }
     }
 
@@ -1305,17 +1305,17 @@ LiteralPropertyName:
     }
 
 LiteralRegExpExpression:
   fields:
     flags:
       block:
         replace: |
           RegExpFlags reflags = JS::RegExpFlag::NoFlags;
-          auto flagsContext = Context(FieldContext(BinASTInterfaceAndField::LiteralRegExpExpression__Flags));
+          auto flagsContext = FieldContext(BinASTInterfaceAndField::LiteralRegExpExpression__Flags);
           if (mozilla::IsSame<Tok, BinASTTokenReaderContext>::value) {
             // Hack: optimized `readChars` is not implemented for `BinASTTokenReaderContext`.
             RootedAtom flags(cx_);
             MOZ_TRY_VAR(flags, tokenizer_->readAtom(flagsContext));
             if (!this->parseRegExpFlags(flags, &reflags)) {
               return raiseError("Invalid regexp flags");
             }
           } else {
--- a/js/src/frontend/BinASTParser.cpp
+++ b/js/src/frontend/BinASTParser.cpp
@@ -48,17 +48,18 @@ bool operator==(const typename Tok::Char
 /*
 AssertedMaybePositionalParameterName ::= AssertedParameterName
     AssertedPositionalParameterName
     AssertedRestParameterName
 */
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseAssertedMaybePositionalParameterName(
     AssertedScopeKind scopeKind,
-    MutableHandle<GCVector<JSAtom*>> positionalParams, const Context& context) {
+    MutableHandle<GCVector<JSAtom*>> positionalParams,
+    const ListContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
 
   BINJS_MOZ_TRY_DECL(
@@ -68,17 +69,18 @@ JS::Result<Ok> BinASTParser<Tok>::parseA
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseSumAssertedMaybePositionalParameterName(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
     AssertedScopeKind scopeKind,
-    MutableHandle<GCVector<JSAtom*>> positionalParams, const Context& context) {
+    MutableHandle<GCVector<JSAtom*>> positionalParams,
+    const ListContext& context) {
   Ok result;
   switch (kind) {
     case BinASTKind::AssertedParameterName:
       return raiseError(
           "FIXME: Not implemented yet in this preview release "
           "(AssertedParameterName)");
     case BinASTKind::AssertedPositionalParameterName:
       MOZ_TRY_VAR(result, parseInterfaceAssertedPositionalParameterName(
@@ -99,17 +101,17 @@ JS::Result<Ok> BinASTParser<Tok>::parseS
 AssignmentTarget ::= ArrayAssignmentTarget
     AssignmentTargetIdentifier
     ComputedMemberAssignmentTarget
     ObjectAssignmentTarget
     StaticMemberAssignmentTarget
 */
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseAssignmentTarget(
-    const Context& context) {
+    const FieldContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
 
   BINJS_MOZ_TRY_DECL(result,
@@ -117,17 +119,17 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseSumAssignmentTarget(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::ArrayAssignmentTarget:
       MOZ_TRY_VAR(result, parseInterfaceArrayAssignmentTarget(start, kind,
                                                               fields, context));
       break;
     case BinASTKind::AssignmentTargetIdentifier:
       MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(
@@ -156,17 +158,17 @@ AssignmentTargetOrForInOfBinding ::= Arr
     AssignmentTargetIdentifier
     ComputedMemberAssignmentTarget
     ForInOfBinding
     ObjectAssignmentTarget
     StaticMemberAssignmentTarget
 */
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseAssignmentTargetOrForInOfBinding(
-    const Context& context) {
+    const FieldContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
 
   BINJS_MOZ_TRY_DECL(result, parseSumAssignmentTargetOrForInOfBinding(
@@ -175,17 +177,17 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseSumAssignmentTargetOrForInOfBinding(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::ArrayAssignmentTarget:
       MOZ_TRY_VAR(result, parseInterfaceArrayAssignmentTarget(start, kind,
                                                               fields, context));
       break;
     case BinASTKind::AssignmentTargetIdentifier:
       MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(
@@ -214,47 +216,48 @@ BinASTParser<Tok>::parseSumAssignmentTar
 }
 
 /*
 Binding ::= ArrayBinding
     BindingIdentifier
     ObjectBinding
 */
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parseBinding(const Context& context) {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseBinding(
+    const FieldContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
 
   BINJS_MOZ_TRY_DECL(result, parseSumBinding(start, kind, fields, context));
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseSumBinding(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::ArrayBinding:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceArrayBinding(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceArrayBinding(start, kind, fields,
+                                                     Context(context)));
       break;
     case BinASTKind::BindingIdentifier:
       MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields,
-                                                          context));
+                                                          Context(context)));
       break;
     case BinASTKind::ObjectBinding:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceObjectBinding(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceObjectBinding(start, kind, fields,
+                                                      Context(context)));
       break;
     default:
       return raiseInvalidKind("Binding", kind);
   }
   return result;
 }
 
 /*
@@ -288,163 +291,163 @@ Expression ::= ArrayExpression
     ThisExpression
     UnaryExpression
     UpdateExpression
     YieldExpression
     YieldStarExpression
 */
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseExpression(
-    const Context& context) {
+    const FieldContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
 
   BINJS_MOZ_TRY_DECL(result, parseSumExpression(start, kind, fields, context));
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseSumExpression(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::ArrayExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceArrayExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields,
+                                                        Context(context)));
       break;
     case BinASTKind::AssignmentExpression:
-      MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind,
-                                                             fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::AwaitExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceAwaitExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields,
+                                                        Context(context)));
       break;
     case BinASTKind::BinaryExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceBinaryExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields,
+                                                         Context(context)));
       break;
     case BinASTKind::CallExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceCallExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields,
+                                                       Context(context)));
       break;
     case BinASTKind::ClassExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceClassExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields,
+                                                        Context(context)));
       break;
     case BinASTKind::CompoundAssignmentExpression:
       MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::ComputedMemberExpression:
       MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::ConditionalExpression:
-      MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind,
-                                                              fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::EagerArrowExpressionWithExpression:
       MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::EagerArrowExpressionWithFunctionBody:
       MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithFunctionBody(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::EagerFunctionExpression:
       MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::IdentifierExpression:
-      MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind,
-                                                             fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LazyArrowExpressionWithExpression:
       MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LazyArrowExpressionWithFunctionBody:
       MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithFunctionBody(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LazyFunctionExpression:
       MOZ_TRY_VAR(result, parseInterfaceLazyFunctionExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralBooleanExpression:
       MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralInfinityExpression:
       MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralNullExpression:
-      MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind,
-                                                              fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralNumericExpression:
       MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralRegExpExpression:
       MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralStringExpression:
       MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::NewExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceNewExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields,
+                                                      Context(context)));
       break;
     case BinASTKind::NewTargetExpression:
       MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields,
-                                                            context));
+                                                            Context(context)));
       break;
     case BinASTKind::ObjectExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceObjectExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields,
+                                                         Context(context)));
       break;
     case BinASTKind::StaticMemberExpression:
       MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::TemplateExpression:
       MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields,
-                                                           context));
+                                                           Context(context)));
       break;
     case BinASTKind::ThisExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceThisExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields,
+                                                       Context(context)));
       break;
     case BinASTKind::UnaryExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceUnaryExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields,
+                                                        Context(context)));
       break;
     case BinASTKind::UpdateExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceUpdateExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields,
+                                                         Context(context)));
       break;
     case BinASTKind::YieldExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceYieldExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields,
+                                                        Context(context)));
       break;
     case BinASTKind::YieldStarExpression:
       MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields,
-                                                            context));
+                                                            Context(context)));
       break;
     default:
       return raiseInvalidKind("Expression", kind);
   }
   return result;
 }
 
 /*
@@ -479,17 +482,17 @@ ExpressionOrSpreadElement ::= ArrayExpre
     ThisExpression
     UnaryExpression
     UpdateExpression
     YieldExpression
     YieldStarExpression
 */
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseExpressionOrSpreadElement(
-    const Context& context) {
+    const ListContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
 
   BINJS_MOZ_TRY_DECL(
@@ -497,150 +500,150 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseSumExpressionOrSpreadElement(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const ListContext& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::ArrayExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceArrayExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields,
+                                                        Context(context)));
       break;
     case BinASTKind::AssignmentExpression:
-      MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind,
-                                                             fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::AwaitExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceAwaitExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields,
+                                                        Context(context)));
       break;
     case BinASTKind::BinaryExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceBinaryExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields,
+                                                         Context(context)));
       break;
     case BinASTKind::CallExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceCallExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields,
+                                                       Context(context)));
       break;
     case BinASTKind::ClassExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceClassExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields,
+                                                        Context(context)));
       break;
     case BinASTKind::CompoundAssignmentExpression:
       MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::ComputedMemberExpression:
       MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::ConditionalExpression:
-      MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind,
-                                                              fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::EagerArrowExpressionWithExpression:
       MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::EagerArrowExpressionWithFunctionBody:
       MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithFunctionBody(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::EagerFunctionExpression:
       MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::IdentifierExpression:
-      MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind,
-                                                             fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LazyArrowExpressionWithExpression:
       MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LazyArrowExpressionWithFunctionBody:
       MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithFunctionBody(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LazyFunctionExpression:
       MOZ_TRY_VAR(result, parseInterfaceLazyFunctionExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralBooleanExpression:
       MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralInfinityExpression:
       MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralNullExpression:
-      MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind,
-                                                              fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralNumericExpression:
       MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralRegExpExpression:
       MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralStringExpression:
       MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::NewExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceNewExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields,
+                                                      Context(context)));
       break;
     case BinASTKind::NewTargetExpression:
       MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields,
-                                                            context));
+                                                            Context(context)));
       break;
     case BinASTKind::ObjectExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceObjectExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields,
+                                                         Context(context)));
       break;
     case BinASTKind::SpreadElement:
       MOZ_TRY_VAR(result,
                   parseInterfaceSpreadElement(start, kind, fields, context));
       break;
     case BinASTKind::StaticMemberExpression:
       MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::TemplateExpression:
       MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields,
-                                                           context));
+                                                           Context(context)));
       break;
     case BinASTKind::ThisExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceThisExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields,
+                                                       Context(context)));
       break;
     case BinASTKind::UnaryExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceUnaryExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields,
+                                                        Context(context)));
       break;
     case BinASTKind::UpdateExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceUpdateExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields,
+                                                         Context(context)));
       break;
     case BinASTKind::YieldExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceYieldExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields,
+                                                        Context(context)));
       break;
     case BinASTKind::YieldStarExpression:
       MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields,
-                                                            context));
+                                                            Context(context)));
       break;
     default:
       return raiseInvalidKind("ExpressionOrSpreadElement", kind);
   }
   return result;
 }
 
 /*
@@ -675,17 +678,17 @@ ExpressionOrSuper ::= ArrayExpression
     ThisExpression
     UnaryExpression
     UpdateExpression
     YieldExpression
     YieldStarExpression
 */
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseExpressionOrSuper(
-    const Context& context) {
+    const FieldContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
 
   BINJS_MOZ_TRY_DECL(result,
@@ -693,294 +696,294 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseSumExpressionOrSuper(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::ArrayExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceArrayExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields,
+                                                        Context(context)));
       break;
     case BinASTKind::AssignmentExpression:
-      MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind,
-                                                             fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::AwaitExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceAwaitExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields,
+                                                        Context(context)));
       break;
     case BinASTKind::BinaryExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceBinaryExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields,
+                                                         Context(context)));
       break;
     case BinASTKind::CallExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceCallExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields,
+                                                       Context(context)));
       break;
     case BinASTKind::ClassExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceClassExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields,
+                                                        Context(context)));
       break;
     case BinASTKind::CompoundAssignmentExpression:
       MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::ComputedMemberExpression:
       MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::ConditionalExpression:
-      MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind,
-                                                              fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::EagerArrowExpressionWithExpression:
       MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::EagerArrowExpressionWithFunctionBody:
       MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithFunctionBody(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::EagerFunctionExpression:
       MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::IdentifierExpression:
-      MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind,
-                                                             fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LazyArrowExpressionWithExpression:
       MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LazyArrowExpressionWithFunctionBody:
       MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithFunctionBody(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LazyFunctionExpression:
       MOZ_TRY_VAR(result, parseInterfaceLazyFunctionExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralBooleanExpression:
       MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralInfinityExpression:
       MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralNullExpression:
-      MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind,
-                                                              fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralNumericExpression:
       MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralRegExpExpression:
       MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralStringExpression:
       MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::NewExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceNewExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields,
+                                                      Context(context)));
       break;
     case BinASTKind::NewTargetExpression:
       MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields,
-                                                            context));
+                                                            Context(context)));
       break;
     case BinASTKind::ObjectExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceObjectExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields,
+                                                         Context(context)));
       break;
     case BinASTKind::StaticMemberExpression:
       MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::Super:
       MOZ_TRY_VAR(result, parseInterfaceSuper(start, kind, fields, context));
       break;
     case BinASTKind::TemplateExpression:
       MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields,
-                                                           context));
+                                                           Context(context)));
       break;
     case BinASTKind::ThisExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceThisExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields,
+                                                       Context(context)));
       break;
     case BinASTKind::UnaryExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceUnaryExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields,
+                                                        Context(context)));
       break;
     case BinASTKind::UpdateExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceUpdateExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields,
+                                                         Context(context)));
       break;
     case BinASTKind::YieldExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceYieldExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields,
+                                                        Context(context)));
       break;
     case BinASTKind::YieldStarExpression:
       MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields,
-                                                            context));
+                                                            Context(context)));
       break;
     default:
       return raiseInvalidKind("ExpressionOrSuper", kind);
   }
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseSumExpressionOrVariableDeclaration(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::ArrayExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceArrayExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceArrayExpression(start, kind, fields,
+                                                        Context(context)));
       break;
     case BinASTKind::AssignmentExpression:
-      MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(start, kind,
-                                                             fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceAssignmentExpression(
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::AwaitExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceAwaitExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceAwaitExpression(start, kind, fields,
+                                                        Context(context)));
       break;
     case BinASTKind::BinaryExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceBinaryExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceBinaryExpression(start, kind, fields,
+                                                         Context(context)));
       break;
     case BinASTKind::CallExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceCallExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceCallExpression(start, kind, fields,
+                                                       Context(context)));
       break;
     case BinASTKind::ClassExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceClassExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceClassExpression(start, kind, fields,
+                                                        Context(context)));
       break;
     case BinASTKind::CompoundAssignmentExpression:
       MOZ_TRY_VAR(result, parseInterfaceCompoundAssignmentExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::ComputedMemberExpression:
       MOZ_TRY_VAR(result, parseInterfaceComputedMemberExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::ConditionalExpression:
-      MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(start, kind,
-                                                              fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceConditionalExpression(
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::EagerArrowExpressionWithExpression:
       MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::EagerArrowExpressionWithFunctionBody:
       MOZ_TRY_VAR(result, parseInterfaceEagerArrowExpressionWithFunctionBody(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::EagerFunctionExpression:
       MOZ_TRY_VAR(result, parseInterfaceEagerFunctionExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::IdentifierExpression:
-      MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(start, kind,
-                                                             fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceIdentifierExpression(
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LazyArrowExpressionWithExpression:
       MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LazyArrowExpressionWithFunctionBody:
       MOZ_TRY_VAR(result, parseInterfaceLazyArrowExpressionWithFunctionBody(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LazyFunctionExpression:
       MOZ_TRY_VAR(result, parseInterfaceLazyFunctionExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralBooleanExpression:
       MOZ_TRY_VAR(result, parseInterfaceLiteralBooleanExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralInfinityExpression:
       MOZ_TRY_VAR(result, parseInterfaceLiteralInfinityExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralNullExpression:
-      MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(start, kind,
-                                                              fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceLiteralNullExpression(
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralNumericExpression:
       MOZ_TRY_VAR(result, parseInterfaceLiteralNumericExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralRegExpExpression:
       MOZ_TRY_VAR(result, parseInterfaceLiteralRegExpExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::LiteralStringExpression:
       MOZ_TRY_VAR(result, parseInterfaceLiteralStringExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::NewExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceNewExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceNewExpression(start, kind, fields,
+                                                      Context(context)));
       break;
     case BinASTKind::NewTargetExpression:
       MOZ_TRY_VAR(result, parseInterfaceNewTargetExpression(start, kind, fields,
-                                                            context));
+                                                            Context(context)));
       break;
     case BinASTKind::ObjectExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceObjectExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceObjectExpression(start, kind, fields,
+                                                         Context(context)));
       break;
     case BinASTKind::StaticMemberExpression:
       MOZ_TRY_VAR(result, parseInterfaceStaticMemberExpression(
-                              start, kind, fields, context));
+                              start, kind, fields, Context(context)));
       break;
     case BinASTKind::TemplateExpression:
       MOZ_TRY_VAR(result, parseInterfaceTemplateExpression(start, kind, fields,
-                                                           context));
+                                                           Context(context)));
       break;
     case BinASTKind::ThisExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceThisExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceThisExpression(start, kind, fields,
+                                                       Context(context)));
       break;
     case BinASTKind::UnaryExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceUnaryExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceUnaryExpression(start, kind, fields,
+                                                        Context(context)));
       break;
     case BinASTKind::UpdateExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceUpdateExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceUpdateExpression(start, kind, fields,
+                                                         Context(context)));
       break;
     case BinASTKind::VariableDeclaration:
       MOZ_TRY_VAR(result, parseInterfaceVariableDeclaration(start, kind, fields,
-                                                            context));
+                                                            Context(context)));
       break;
     case BinASTKind::YieldExpression:
-      MOZ_TRY_VAR(result,
-                  parseInterfaceYieldExpression(start, kind, fields, context));
+      MOZ_TRY_VAR(result, parseInterfaceYieldExpression(start, kind, fields,
+                                                        Context(context)));
       break;
     case BinASTKind::YieldStarExpression:
       MOZ_TRY_VAR(result, parseInterfaceYieldStarExpression(start, kind, fields,
-                                                            context));
+                                                            Context(context)));
       break;
     default:
       return raiseInvalidKind("ExpressionOrVariableDeclaration", kind);
   }
   return result;
 }
 
 /*
@@ -990,17 +993,17 @@ ObjectProperty ::= DataProperty
     EagerSetter
     LazyGetter
     LazyMethod
     LazySetter
     ShorthandProperty
 */
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseObjectProperty(
-    const Context& context) {
+    const ListContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
 
   BINJS_MOZ_TRY_DECL(result,
@@ -1008,17 +1011,17 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseSumObjectProperty(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const ListContext& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::DataProperty:
       MOZ_TRY_VAR(result,
                   parseInterfaceDataProperty(start, kind, fields, context));
       break;
     case BinASTKind::EagerGetter:
       MOZ_TRY_VAR(result,
@@ -1111,34 +1114,35 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   return result;
 }
 
 /*
 Program ::= Module
     Script
 */
 template <typename Tok>
-JS::Result<ParseNode*> BinASTParser<Tok>::parseProgram(const Context& context) {
+JS::Result<ParseNode*> BinASTParser<Tok>::parseProgram(
+    const RootContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
 
   BINJS_MOZ_TRY_DECL(result, parseSumProgram(start, kind, fields, context));
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseSumProgram(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const RootContext& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::Module:
       MOZ_TRY_VAR(result, parseInterfaceModule(start, kind, fields, context));
       break;
     case BinASTKind::Script:
       MOZ_TRY_VAR(result, parseInterfaceScript(start, kind, fields, context));
       break;
@@ -1149,17 +1153,17 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 }
 
 /*
 PropertyName ::= ComputedPropertyName
     LiteralPropertyName
 */
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parsePropertyName(
-    const Context& context) {
+    const FieldContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
 
   BINJS_MOZ_TRY_DECL(result,
@@ -1167,17 +1171,17 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseSumPropertyName(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::ComputedPropertyName:
       MOZ_TRY_VAR(result, parseInterfaceComputedPropertyName(start, kind,
                                                              fields, context));
       break;
     case BinASTKind::LiteralPropertyName:
       MOZ_TRY_VAR(result, parseInterfaceLiteralPropertyName(start, kind, fields,
@@ -1191,17 +1195,17 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 
 /*
 SimpleAssignmentTarget ::= AssignmentTargetIdentifier
     ComputedMemberAssignmentTarget
     StaticMemberAssignmentTarget
 */
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseSimpleAssignmentTarget(
-    const Context& context) {
+    const FieldContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
   const auto start = tokenizer_->offset();
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
 
   BINJS_MOZ_TRY_DECL(
@@ -1209,17 +1213,17 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseSumSimpleAssignmentTarget(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   ParseNode* result;
   switch (kind) {
     case BinASTKind::AssignmentTargetIdentifier:
       MOZ_TRY_VAR(result, parseInterfaceAssignmentTargetIdentifier(
                               start, kind, fields, context));
       break;
     case BinASTKind::ComputedMemberAssignmentTarget:
       MOZ_TRY_VAR(result, parseInterfaceComputedMemberAssignmentTarget(
@@ -1385,17 +1389,17 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 }
 
 // ----- Interfaces (autogenerated, by lexicographical order)
 // When fields have a non-trivial type, implementation is deanonymized and
 // delegated to another parser.
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceArrayAssignmentTarget(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release "
       "(ArrayAssignmentTarget)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceArrayBinding(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
@@ -1411,37 +1415,36 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   MOZ_ASSERT(kind == BinASTKind::ArrayExpression);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Elements};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(
-      elements,
-      parseListOfOptionalExpressionOrSpreadElement(Context(
-          FieldContext(BinASTInterfaceAndField::ArrayExpression__Elements))));
+  BINJS_MOZ_TRY_DECL(elements,
+                     parseListOfOptionalExpressionOrSpreadElement(FieldContext(
+                         BinASTInterfaceAndField::ArrayExpression__Elements)));
 
   if (elements->empty()) {
     elements->setHasNonConstInitializer();
   }
   auto result = elements;
   return result;
 }
 
 /*
  interface AssertedBlockScope : Node {
     FrozenArray<AssertedDeclaredName> declaredNames;
     bool hasDirectEval;
  }
 */
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseAssertedBlockScope(
-    const Context& context) {
+    const FieldContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::AssertedBlockScope) {
     return raiseInvalidKind("AssertedBlockScope", kind);
   }
@@ -1451,36 +1454,36 @@ JS::Result<Ok> BinASTParser<Tok>::parseA
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedBlockScope(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   MOZ_ASSERT(kind == BinASTKind::AssertedBlockScope);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::DeclaredNames,
                                           BinASTField::HasDirectEval};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto scopeKind = AssertedScopeKind::Block;
 
   MOZ_TRY(parseListOfAssertedDeclaredName(
       scopeKind,
-      Context(FieldContext(
-          BinASTInterfaceAndField::AssertedBlockScope__DeclaredNames))));
+      FieldContext(
+          BinASTInterfaceAndField::AssertedBlockScope__DeclaredNames)));
 
   BINJS_MOZ_TRY_DECL(
       hasDirectEval,
-      tokenizer_->readBool(Context(FieldContext(
-          BinASTInterfaceAndField::AssertedBlockScope__HasDirectEval))));
+      tokenizer_->readBool(FieldContext(
+          BinASTInterfaceAndField::AssertedBlockScope__HasDirectEval)));
   if (hasDirectEval) {
     pc_->sc()->setHasDirectEval();
     pc_->sc()->setBindingsAccessedDynamically();
   }
   if (hasDirectEval && pc_->isFunctionBox() && !pc_->sc()->strict()) {
     // In non-strict mode code, direct calls to eval can
     // add variables to the call object.
     pc_->functionBox()->setHasExtensibleScope();
@@ -1492,17 +1495,17 @@ JS::Result<Ok> BinASTParser<Tok>::parseI
 /*
  interface AssertedBoundName : Node {
     [IdentifierName] string name;
     bool isCaptured;
  }
 */
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseAssertedBoundName(
-    AssertedScopeKind scopeKind, const Context& context) {
+    AssertedScopeKind scopeKind, const ListContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::AssertedBoundName) {
     return raiseInvalidKind("AssertedBoundName", kind);
   }
@@ -1512,35 +1515,34 @@ JS::Result<Ok> BinASTParser<Tok>::parseA
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedBoundName(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    AssertedScopeKind scopeKind, const Context& context) {
+    AssertedScopeKind scopeKind, const ListContext& context) {
   MOZ_ASSERT(kind == BinASTKind::AssertedBoundName);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Name,
                                           BinASTField::IsCaptured};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const bool allowDuplicateName = false;
 
   RootedAtom name(cx_);
-  MOZ_TRY_VAR(name, tokenizer_->readIdentifierName(Context(FieldContext(
-                        BinASTInterfaceAndField::AssertedBoundName__Name))));
+  MOZ_TRY_VAR(name, tokenizer_->readIdentifierName(FieldContext(
+                        BinASTInterfaceAndField::AssertedBoundName__Name)));
 
   BINJS_MOZ_TRY_DECL(
-      isCaptured,
-      tokenizer_->readBool(Context(FieldContext(
-          BinASTInterfaceAndField::AssertedBoundName__IsCaptured))));
+      isCaptured, tokenizer_->readBool(FieldContext(
+                      BinASTInterfaceAndField::AssertedBoundName__IsCaptured)));
   ParseContext::Scope* scope;
   DeclarationKind declKind;
   MOZ_TRY(getBoundScope(scopeKind, scope, declKind));
   MOZ_TRY(addScopeName(scopeKind, name, scope, declKind, isCaptured,
                        allowDuplicateName));
   auto result = Ok();
   return result;
 }
@@ -1548,17 +1550,17 @@ JS::Result<Ok> BinASTParser<Tok>::parseI
 /*
  interface AssertedBoundNamesScope : Node {
     FrozenArray<AssertedBoundName> boundNames;
     bool hasDirectEval;
  }
 */
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseAssertedBoundNamesScope(
-    const Context& context) {
+    const FieldContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::AssertedBoundNamesScope) {
     return raiseInvalidKind("AssertedBoundNamesScope", kind);
   }
@@ -1568,36 +1570,36 @@ JS::Result<Ok> BinASTParser<Tok>::parseA
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedBoundNamesScope(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   MOZ_ASSERT(kind == BinASTKind::AssertedBoundNamesScope);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::BoundNames,
                                           BinASTField::HasDirectEval};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto scopeKind = AssertedScopeKind::Catch;
 
   MOZ_TRY(parseListOfAssertedBoundName(
       scopeKind,
-      Context(FieldContext(
-          BinASTInterfaceAndField::AssertedBoundNamesScope__BoundNames))));
+      FieldContext(
+          BinASTInterfaceAndField::AssertedBoundNamesScope__BoundNames)));
 
   BINJS_MOZ_TRY_DECL(
       hasDirectEval,
-      tokenizer_->readBool(Context(FieldContext(
-          BinASTInterfaceAndField::AssertedBoundNamesScope__HasDirectEval))));
+      tokenizer_->readBool(FieldContext(
+          BinASTInterfaceAndField::AssertedBoundNamesScope__HasDirectEval)));
   if (hasDirectEval) {
     pc_->sc()->setHasDirectEval();
     pc_->sc()->setBindingsAccessedDynamically();
   }
   if (hasDirectEval && pc_->isFunctionBox() && !pc_->sc()->strict()) {
     // In non-strict mode code, direct calls to eval can
     // add variables to the call object.
     pc_->functionBox()->setHasExtensibleScope();
@@ -1610,17 +1612,17 @@ JS::Result<Ok> BinASTParser<Tok>::parseI
  interface AssertedDeclaredName : Node {
     [IdentifierName] string name;
     AssertedDeclaredKind kind;
     bool isCaptured;
  }
 */
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseAssertedDeclaredName(
-    AssertedScopeKind scopeKind, const Context& context) {
+    AssertedScopeKind scopeKind, const ListContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::AssertedDeclaredName) {
     return raiseInvalidKind("AssertedDeclaredName", kind);
   }
@@ -1630,44 +1632,44 @@ JS::Result<Ok> BinASTParser<Tok>::parseA
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedDeclaredName(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    AssertedScopeKind scopeKind, const Context& context) {
+    AssertedScopeKind scopeKind, const ListContext& context) {
   MOZ_ASSERT(kind == BinASTKind::AssertedDeclaredName);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {BinASTField::Name, BinASTField::Kind,
                                           BinASTField::IsCaptured};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const bool allowDuplicateName = false;
 
   RootedAtom name(cx_);
-  MOZ_TRY_VAR(name, tokenizer_->readIdentifierName(Context(FieldContext(
-                        BinASTInterfaceAndField::AssertedDeclaredName__Name))));
-
-  BINJS_MOZ_TRY_DECL(
-      kind_, parseAssertedDeclaredKind(Context(FieldContext(
-                 BinASTInterfaceAndField::AssertedDeclaredName__Kind))));
+  MOZ_TRY_VAR(name, tokenizer_->readIdentifierName(FieldContext(
+                        BinASTInterfaceAndField::AssertedDeclaredName__Name)));
+
+  BINJS_MOZ_TRY_DECL(kind_,
+                     parseAssertedDeclaredKind(FieldContext(
+                         BinASTInterfaceAndField::AssertedDeclaredName__Kind)));
   if (kind_ == AssertedDeclaredKind::NonConstLexical) {
     return raiseError("Let is not supported in this preview release");
   }
   if (kind_ == AssertedDeclaredKind::ConstLexical) {
     return raiseError("Const is not supported in this preview release");
   }
   BINJS_MOZ_TRY_DECL(
       isCaptured,
-      tokenizer_->readBool(Context(FieldContext(
-          BinASTInterfaceAndField::AssertedDeclaredName__IsCaptured))));
+      tokenizer_->readBool(FieldContext(
+          BinASTInterfaceAndField::AssertedDeclaredName__IsCaptured)));
   ParseContext::Scope* scope;
   DeclarationKind declKind;
   MOZ_TRY(getDeclaredScope(scopeKind, kind_, scope, declKind));
   MOZ_TRY(addScopeName(scopeKind, name, scope, declKind, isCaptured,
                        allowDuplicateName));
   auto result = Ok();
   return result;
 }
@@ -1676,17 +1678,18 @@ JS::Result<Ok> BinASTParser<Tok>::parseI
  interface AssertedParameterScope : Node {
     FrozenArray<AssertedMaybePositionalParameterName> paramNames;
     bool hasDirectEval;
     bool isSimpleParameterList;
  }
 */
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseAssertedParameterScope(
-    MutableHandle<GCVector<JSAtom*>> positionalParams, const Context& context) {
+    MutableHandle<GCVector<JSAtom*>> positionalParams,
+    const FieldContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::AssertedParameterScope) {
     return raiseInvalidKind("AssertedParameterScope", kind);
   }
@@ -1697,80 +1700,82 @@ JS::Result<Ok> BinASTParser<Tok>::parseA
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedParameterScope(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    MutableHandle<GCVector<JSAtom*>> positionalParams, const Context& context) {
+    MutableHandle<GCVector<JSAtom*>> positionalParams,
+    const FieldContext& context) {
   MOZ_ASSERT(kind == BinASTKind::AssertedParameterScope);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {BinASTField::ParamNames,
                                           BinASTField::HasDirectEval,
                                           BinASTField::IsSimpleParameterList};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto scopeKind = AssertedScopeKind::Parameter;
 
   MOZ_TRY(parseListOfAssertedMaybePositionalParameterName(
       scopeKind, positionalParams,
-      Context(FieldContext(
-          BinASTInterfaceAndField::AssertedParameterScope__ParamNames))));
+      FieldContext(
+          BinASTInterfaceAndField::AssertedParameterScope__ParamNames)));
 
   BINJS_MOZ_TRY_DECL(
       hasDirectEval,
-      tokenizer_->readBool(Context(FieldContext(
-          BinASTInterfaceAndField::AssertedParameterScope__HasDirectEval))));
+      tokenizer_->readBool(FieldContext(
+          BinASTInterfaceAndField::AssertedParameterScope__HasDirectEval)));
   if (hasDirectEval) {
     pc_->sc()->setHasDirectEval();
     pc_->sc()->setBindingsAccessedDynamically();
   }
   BINJS_MOZ_TRY_DECL(isSimpleParameterList,
-                     tokenizer_->readBool(Context(FieldContext(
+                     tokenizer_->readBool(FieldContext(
                          BinASTInterfaceAndField::
-                             AssertedParameterScope__IsSimpleParameterList))));
+                             AssertedParameterScope__IsSimpleParameterList)));
   (void)isSimpleParameterList;
   if (hasDirectEval && pc_->isFunctionBox() && !pc_->sc()->strict()) {
     // In non-strict mode code, direct calls to eval can
     // add variables to the call object.
     pc_->functionBox()->setHasExtensibleScope();
   }
   auto result = Ok();
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedPositionalParameterName(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
     AssertedScopeKind scopeKind,
-    MutableHandle<GCVector<JSAtom*>> positionalParams, const Context& context) {
+    MutableHandle<GCVector<JSAtom*>> positionalParams,
+    const ListContext& context) {
   MOZ_ASSERT(kind == BinASTKind::AssertedPositionalParameterName);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {BinASTField::Index, BinASTField::Name,
                                           BinASTField::IsCaptured};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   bool allowDuplicateName = !pc_->sc()->strict();
 
   BINJS_MOZ_TRY_DECL(
       index,
-      tokenizer_->readUnsignedLong(Context(FieldContext(
-          BinASTInterfaceAndField::AssertedPositionalParameterName__Index))));
+      tokenizer_->readUnsignedLong(FieldContext(
+          BinASTInterfaceAndField::AssertedPositionalParameterName__Index)));
 
   RootedAtom name(cx_);
   MOZ_TRY_VAR(
       name,
-      tokenizer_->readIdentifierName(Context(FieldContext(
-          BinASTInterfaceAndField::AssertedPositionalParameterName__Name))));
+      tokenizer_->readIdentifierName(FieldContext(
+          BinASTInterfaceAndField::AssertedPositionalParameterName__Name)));
   // `positionalParams` vector can be shorter than the actual
   // parameter length. Resize on demand.
   // (see also ListOfAssertedMaybePositionalParameterName)
   size_t prevLength = positionalParams.get().length();
   if (index >= prevLength) {
     // This is implementation limit, which is not in the spec.
     if (index >= ARGNO_LIMIT - 1) {
       return raiseError("AssertedPositionalParameterName.index is too big");
@@ -1784,19 +1789,19 @@ JS::Result<Ok> BinASTParser<Tok>::parseI
 
   if (positionalParams.get()[index]) {
     return raiseError(
         "AssertedPositionalParameterName has duplicate entry for the same "
         "index");
   }
   positionalParams.get()[index] = name;
   BINJS_MOZ_TRY_DECL(isCaptured,
-                     tokenizer_->readBool(Context(FieldContext(
+                     tokenizer_->readBool(FieldContext(
                          BinASTInterfaceAndField::
-                             AssertedPositionalParameterName__IsCaptured))));
+                             AssertedPositionalParameterName__IsCaptured)));
   ParseContext::Scope* scope;
   DeclarationKind declKind;
   MOZ_TRY(getBoundScope(scopeKind, scope, declKind));
   MOZ_TRY(addScopeName(scopeKind, name, scope, declKind, isCaptured,
                        allowDuplicateName));
   auto result = Ok();
   return result;
 }
@@ -1804,17 +1809,17 @@ JS::Result<Ok> BinASTParser<Tok>::parseI
 /*
  interface AssertedScriptGlobalScope : Node {
     FrozenArray<AssertedDeclaredName> declaredNames;
     bool hasDirectEval;
  }
 */
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseAssertedScriptGlobalScope(
-    const Context& context) {
+    const FieldContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::AssertedScriptGlobalScope) {
     return raiseInvalidKind("AssertedScriptGlobalScope", kind);
   }
@@ -1824,36 +1829,36 @@ JS::Result<Ok> BinASTParser<Tok>::parseA
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedScriptGlobalScope(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   MOZ_ASSERT(kind == BinASTKind::AssertedScriptGlobalScope);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::DeclaredNames,
                                           BinASTField::HasDirectEval};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto scopeKind = AssertedScopeKind::Global;
 
   MOZ_TRY(parseListOfAssertedDeclaredName(
       scopeKind,
-      Context(FieldContext(
-          BinASTInterfaceAndField::AssertedScriptGlobalScope__DeclaredNames))));
+      FieldContext(
+          BinASTInterfaceAndField::AssertedScriptGlobalScope__DeclaredNames)));
 
   BINJS_MOZ_TRY_DECL(
       hasDirectEval,
-      tokenizer_->readBool(Context(FieldContext(
-          BinASTInterfaceAndField::AssertedScriptGlobalScope__HasDirectEval))));
+      tokenizer_->readBool(FieldContext(
+          BinASTInterfaceAndField::AssertedScriptGlobalScope__HasDirectEval)));
   if (hasDirectEval) {
     pc_->sc()->setHasDirectEval();
     pc_->sc()->setBindingsAccessedDynamically();
   }
   if (hasDirectEval && pc_->isFunctionBox() && !pc_->sc()->strict()) {
     // In non-strict mode code, direct calls to eval can
     // add variables to the call object.
     pc_->functionBox()->setHasExtensibleScope();
@@ -1865,17 +1870,17 @@ JS::Result<Ok> BinASTParser<Tok>::parseI
 /*
  interface AssertedVarScope : Node {
     FrozenArray<AssertedDeclaredName> declaredNames;
     bool hasDirectEval;
  }
 */
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseAssertedVarScope(
-    const Context& context) {
+    const FieldContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::AssertedVarScope) {
     return raiseInvalidKind("AssertedVarScope", kind);
   }
@@ -1885,36 +1890,35 @@ JS::Result<Ok> BinASTParser<Tok>::parseA
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseInterfaceAssertedVarScope(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   MOZ_ASSERT(kind == BinASTKind::AssertedVarScope);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::DeclaredNames,
                                           BinASTField::HasDirectEval};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto scopeKind = AssertedScopeKind::Var;
 
   MOZ_TRY(parseListOfAssertedDeclaredName(
       scopeKind,
-      Context(FieldContext(
-          BinASTInterfaceAndField::AssertedVarScope__DeclaredNames))));
+      FieldContext(BinASTInterfaceAndField::AssertedVarScope__DeclaredNames)));
 
   BINJS_MOZ_TRY_DECL(
       hasDirectEval,
-      tokenizer_->readBool(Context(FieldContext(
-          BinASTInterfaceAndField::AssertedVarScope__HasDirectEval))));
+      tokenizer_->readBool(FieldContext(
+          BinASTInterfaceAndField::AssertedVarScope__HasDirectEval)));
   if (hasDirectEval) {
     pc_->sc()->setHasDirectEval();
     pc_->sc()->setBindingsAccessedDynamically();
   }
   if (hasDirectEval && pc_->isFunctionBox() && !pc_->sc()->strict()) {
     // In non-strict mode code, direct calls to eval can
     // add variables to the call object.
     pc_->functionBox()->setHasExtensibleScope();
@@ -1932,46 +1936,46 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Binding,
                                           BinASTField::Expression};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   BINJS_MOZ_TRY_DECL(
-      binding, parseAssignmentTarget(Context(FieldContext(
-                   BinASTInterfaceAndField::AssignmentExpression__Binding))));
+      binding, parseAssignmentTarget(FieldContext(
+                   BinASTInterfaceAndField::AssignmentExpression__Binding)));
 
   BINJS_MOZ_TRY_DECL(
       expression,
-      parseExpression(Context(FieldContext(
-          BinASTInterfaceAndField::AssignmentExpression__Expression))));
+      parseExpression(FieldContext(
+          BinASTInterfaceAndField::AssignmentExpression__Expression)));
 
   BINJS_TRY_DECL(result, handler_.newAssignment(ParseNodeKind::AssignExpr,
                                                 binding, expression));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceAssignmentTargetIdentifier(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   MOZ_ASSERT(kind == BinASTKind::AssignmentTargetIdentifier);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Name};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   RootedAtom name(cx_);
   MOZ_TRY_VAR(name,
-              tokenizer_->readIdentifierName(Context(FieldContext(
-                  BinASTInterfaceAndField::AssignmentTargetIdentifier__Name))));
+              tokenizer_->readIdentifierName(FieldContext(
+                  BinASTInterfaceAndField::AssignmentTargetIdentifier__Name)));
 
   BINJS_TRY(usedNames_.noteUse(cx_, name, pc_->scriptId(),
                                pc_->innermostScope()->id()));
   BINJS_TRY_DECL(result, handler_.newName(name->asPropertyName(),
                                           tokenizer_->pos(start), cx_));
   return result;
 }
 
@@ -1991,27 +1995,27 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {
       BinASTField::Operator, BinASTField::Left, BinASTField::Right};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
+  BINJS_MOZ_TRY_DECL(operator_,
+                     parseBinaryOperator(FieldContext(
+                         BinASTInterfaceAndField::BinaryExpression__Operator)));
+
   BINJS_MOZ_TRY_DECL(
-      operator_, parseBinaryOperator(Context(FieldContext(
-                     BinASTInterfaceAndField::BinaryExpression__Operator))));
-
-  BINJS_MOZ_TRY_DECL(left,
-                     parseExpression(Context(FieldContext(
-                         BinASTInterfaceAndField::BinaryExpression__Left))));
+      left, parseExpression(
+                FieldContext(BinASTInterfaceAndField::BinaryExpression__Left)));
 
   BINJS_MOZ_TRY_DECL(right,
-                     parseExpression(Context(FieldContext(
-                         BinASTInterfaceAndField::BinaryExpression__Right))));
+                     parseExpression(FieldContext(
+                         BinASTInterfaceAndField::BinaryExpression__Right)));
 
   ParseNodeKind pnk;
   switch (operator_) {
     case BinaryOperator::Comma:
       pnk = ParseNodeKind::CommaExpr;
       break;
     case BinaryOperator::LogicalOr:
       pnk = ParseNodeKind::OrExpr;
@@ -2135,18 +2139,18 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Name};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   RootedAtom name(cx_);
-  MOZ_TRY_VAR(name, tokenizer_->readIdentifierName(Context(FieldContext(
-                        BinASTInterfaceAndField::BindingIdentifier__Name))));
+  MOZ_TRY_VAR(name, tokenizer_->readIdentifierName(FieldContext(
+                        BinASTInterfaceAndField::BindingIdentifier__Name)));
 
   BINJS_TRY_DECL(result, handler_.newName(name->asPropertyName(),
                                           tokenizer_->pos(start), cx_));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceBindingWithInitializer(
@@ -2192,21 +2196,21 @@ JS::Result<ParseNode*> BinASTParser<Tok>
                                           BinASTField::Statements};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   ParseContext::Statement stmt(pc_, StatementKind::Block);
   ParseContext::Scope currentScope(cx_, pc_, usedNames_);
   BINJS_TRY(currentScope.init(pc_));
 
   MOZ_TRY(parseAssertedBlockScope(
-      Context(FieldContext(BinASTInterfaceAndField::Block__Scope))));
+      FieldContext(BinASTInterfaceAndField::Block__Scope)));
 
   BINJS_MOZ_TRY_DECL(statements,
-                     parseListOfStatement(Context(FieldContext(
-                         BinASTInterfaceAndField::Block__Statements))));
+                     parseListOfStatement(FieldContext(
+                         BinASTInterfaceAndField::Block__Statements)));
 
   MOZ_TRY(checkClosedVars(currentScope));
   BINJS_TRY_DECL(bindings, NewLexicalScopeData(cx_, currentScope, alloc_, pc_));
   BINJS_TRY_DECL(result, handler_.newLexicalScope(*bindings, statements));
   return result;
 }
 
 template <typename Tok>
@@ -2216,18 +2220,18 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   MOZ_ASSERT(kind == BinASTKind::BreakStatement);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Label};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   RootedAtom label(cx_);
-  MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom(Context(FieldContext(
-                         BinASTInterfaceAndField::BreakStatement__Label))));
+  MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom(FieldContext(
+                         BinASTInterfaceAndField::BreakStatement__Label)));
 
   if (label) {
     if (!IsIdentifier(label)) {
       return raiseError("Invalid identifier");
     }
   }
 
   auto validity =
@@ -2258,22 +2262,22 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Callee,
                                           BinASTField::Arguments};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   BINJS_MOZ_TRY_DECL(callee,
-                     parseExpressionOrSuper(Context(FieldContext(
-                         BinASTInterfaceAndField::CallExpression__Callee))));
+                     parseExpressionOrSuper(FieldContext(
+                         BinASTInterfaceAndField::CallExpression__Callee)));
 
   BINJS_MOZ_TRY_DECL(arguments,
-                     parseArguments(Context(FieldContext(
-                         BinASTInterfaceAndField::CallExpression__Arguments))));
+                     parseArguments(FieldContext(
+                         BinASTInterfaceAndField::CallExpression__Arguments)));
 
   auto op = JSOP_CALL;
 
   // Try to optimize funcall and funapply at the bytecode level
   if (PropertyName* prop = handler_.maybeDottedProperty(callee)) {
     if (prop == cx_->names().apply) {
       op = JSOP_FUNAPPLY;
       if (pc_->isFunctionBox()) {
@@ -2305,17 +2309,17 @@ JS::Result<ParseNode*> BinASTParser<Tok>
  interface CatchClause : Node {
     AssertedBoundNamesScope bindingScope;
     Binding binding;
     Block body;
  }
 */
 template <typename Tok>
 JS::Result<LexicalScopeNode*> BinASTParser<Tok>::parseCatchClause(
-    const Context& context) {
+    const FieldContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::CatchClause) {
     return raiseInvalidKind("CatchClause", kind);
   }
@@ -2325,35 +2329,35 @@ JS::Result<LexicalScopeNode*> BinASTPars
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<LexicalScopeNode*> BinASTParser<Tok>::parseInterfaceCatchClause(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   MOZ_ASSERT(kind == BinASTKind::CatchClause);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {
       BinASTField::BindingScope, BinASTField::Binding, BinASTField::Body};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   ParseContext::Statement stmt(pc_, StatementKind::Catch);
   ParseContext::Scope currentScope(cx_, pc_, usedNames_);
   BINJS_TRY(currentScope.init(pc_));
 
-  MOZ_TRY(parseAssertedBoundNamesScope(Context(
-      FieldContext(BinASTInterfaceAndField::CatchClause__BindingScope))));
+  MOZ_TRY(parseAssertedBoundNamesScope(
+      FieldContext(BinASTInterfaceAndField::CatchClause__BindingScope)));
 
   BINJS_MOZ_TRY_DECL(binding,
-                     parseBinding(Context(FieldContext(
-                         BinASTInterfaceAndField::CatchClause__Binding))));
+                     parseBinding(FieldContext(
+                         BinASTInterfaceAndField::CatchClause__Binding)));
   if (!currentScope.lookupDeclaredName(
           binding->template as<NameNode>().atom())) {
     return raiseError("Missing catch variable in scope");
   }
   BINJS_MOZ_TRY_DECL(body, parseBlock(Context(FieldContext(
                                BinASTInterfaceAndField::CatchClause__Body))));
 
   MOZ_TRY(checkClosedVars(currentScope));
@@ -2390,28 +2394,28 @@ BinASTParser<Tok>::parseInterfaceCompoun
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {
       BinASTField::Operator, BinASTField::Binding, BinASTField::Expression};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   BINJS_MOZ_TRY_DECL(
       operator_,
-      parseCompoundAssignmentOperator(Context(FieldContext(
-          BinASTInterfaceAndField::CompoundAssignmentExpression__Operator))));
+      parseCompoundAssignmentOperator(FieldContext(
+          BinASTInterfaceAndField::CompoundAssignmentExpression__Operator)));
 
   BINJS_MOZ_TRY_DECL(
       binding,
-      parseSimpleAssignmentTarget(Context(FieldContext(
-          BinASTInterfaceAndField::CompoundAssignmentExpression__Binding))));
+      parseSimpleAssignmentTarget(FieldContext(
+          BinASTInterfaceAndField::CompoundAssignmentExpression__Binding)));
 
   BINJS_MOZ_TRY_DECL(
       expression,
-      parseExpression(Context(FieldContext(
-          BinASTInterfaceAndField::CompoundAssignmentExpression__Expression))));
+      parseExpression(FieldContext(
+          BinASTInterfaceAndField::CompoundAssignmentExpression__Expression)));
 
   ParseNodeKind pnk;
   switch (operator_) {
     case CompoundAssignmentOperator::PlusAssign:
       pnk = ParseNodeKind::AddAssignExpr;
       break;
     case CompoundAssignmentOperator::MinusAssign:
       pnk = ParseNodeKind::SubAssignExpr;
@@ -2450,35 +2454,35 @@ BinASTParser<Tok>::parseInterfaceCompoun
   BINJS_TRY_DECL(result, handler_.newAssignment(pnk, binding, expression));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceComputedMemberAssignmentTarget(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   MOZ_ASSERT(kind == BinASTKind::ComputedMemberAssignmentTarget);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Object,
                                           BinASTField::Expression};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   BINJS_MOZ_TRY_DECL(
       object,
-      parseExpressionOrSuper(Context(FieldContext(
-          BinASTInterfaceAndField::ComputedMemberAssignmentTarget__Object))));
+      parseExpressionOrSuper(FieldContext(
+          BinASTInterfaceAndField::ComputedMemberAssignmentTarget__Object)));
 
   BINJS_MOZ_TRY_DECL(expression,
-                     parseExpression(Context(FieldContext(
+                     parseExpression(FieldContext(
                          BinASTInterfaceAndField::
-                             ComputedMemberAssignmentTarget__Expression))));
+                             ComputedMemberAssignmentTarget__Expression)));
 
   BINJS_TRY_DECL(result, handler_.newPropertyByValue(object, expression,
                                                      tokenizer_->offset()));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
@@ -2490,33 +2494,33 @@ BinASTParser<Tok>::parseInterfaceCompute
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Object,
                                           BinASTField::Expression};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   BINJS_MOZ_TRY_DECL(
-      object, parseExpressionOrSuper(Context(FieldContext(
-                  BinASTInterfaceAndField::ComputedMemberExpression__Object))));
+      object, parseExpressionOrSuper(FieldContext(
+                  BinASTInterfaceAndField::ComputedMemberExpression__Object)));
 
   BINJS_MOZ_TRY_DECL(
       expression,
-      parseExpression(Context(FieldContext(
-          BinASTInterfaceAndField::ComputedMemberExpression__Expression))));
+      parseExpression(FieldContext(
+          BinASTInterfaceAndField::ComputedMemberExpression__Expression)));
 
   BINJS_TRY_DECL(result, handler_.newPropertyByValue(object, expression,
                                                      tokenizer_->offset()));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceComputedPropertyName(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release "
       "(ComputedPropertyName)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceConditionalExpression(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
@@ -2526,28 +2530,28 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {
       BinASTField::Test, BinASTField::Consequent, BinASTField::Alternate};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   BINJS_MOZ_TRY_DECL(
-      test, parseExpression(Context(FieldContext(
-                BinASTInterfaceAndField::ConditionalExpression__Test))));
+      test, parseExpression(FieldContext(
+                BinASTInterfaceAndField::ConditionalExpression__Test)));
 
   BINJS_MOZ_TRY_DECL(
       consequent,
-      parseExpression(Context(FieldContext(
-          BinASTInterfaceAndField::ConditionalExpression__Consequent))));
+      parseExpression(FieldContext(
+          BinASTInterfaceAndField::ConditionalExpression__Consequent)));
 
   BINJS_MOZ_TRY_DECL(
       alternate,
-      parseExpression(Context(FieldContext(
-          BinASTInterfaceAndField::ConditionalExpression__Alternate))));
+      parseExpression(FieldContext(
+          BinASTInterfaceAndField::ConditionalExpression__Alternate)));
 
   BINJS_TRY_DECL(result, handler_.newConditional(test, consequent, alternate));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceContinueStatement(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
@@ -2555,18 +2559,18 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   MOZ_ASSERT(kind == BinASTKind::ContinueStatement);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Label};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   RootedAtom label(cx_);
-  MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom(Context(FieldContext(
-                         BinASTInterfaceAndField::ContinueStatement__Label))));
+  MOZ_TRY_VAR(label, tokenizer_->readMaybeAtom(FieldContext(
+                         BinASTInterfaceAndField::ContinueStatement__Label)));
 
   if (label) {
     if (!IsIdentifier(label)) {
       return raiseError("ContinueStatement - Label MUST be an identifier");
     }
   }
 
   auto validity =
@@ -2586,32 +2590,32 @@ JS::Result<ParseNode*> BinASTParser<Tok>
                              label ? label->asPropertyName() : nullptr,
                              tokenizer_->pos(start)));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceDataProperty(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const ListContext& context) {
   MOZ_ASSERT(kind == BinASTKind::DataProperty);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Name,
                                           BinASTField::Expression};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(name, parsePropertyName(Context(FieldContext(
-                               BinASTInterfaceAndField::DataProperty__Name))));
+  BINJS_MOZ_TRY_DECL(name, parsePropertyName(FieldContext(
+                               BinASTInterfaceAndField::DataProperty__Name)));
 
   BINJS_MOZ_TRY_DECL(expression,
-                     parseExpression(Context(FieldContext(
-                         BinASTInterfaceAndField::DataProperty__Expression))));
+                     parseExpression(FieldContext(
+                         BinASTInterfaceAndField::DataProperty__Expression)));
 
   if (!handler_.isUsableAsObjectPropertyName(name)) {
     return raiseError("DataProperty key kind");
   }
 
   ParseNode* result;
   if (name->template is<NameNode>() &&
       name->template as<NameNode>().atom() == cx_->names().proto) {
@@ -2634,17 +2638,17 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 
 /*
  interface Directive : Node {
     string rawValue;
  }
 */
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseDirective(
-    const Context& context) {
+    const ListContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::Directive) {
     return raiseInvalidKind("Directive", kind);
   }
@@ -2654,28 +2658,28 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceDirective(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const ListContext& context) {
   MOZ_ASSERT(kind == BinASTKind::Directive);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::RawValue};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   RootedAtom rawValue(cx_);
-  MOZ_TRY_VAR(rawValue, tokenizer_->readAtom(Context(FieldContext(
-                            BinASTInterfaceAndField::Directive__RawValue))));
+  MOZ_TRY_VAR(rawValue, tokenizer_->readAtom(FieldContext(
+                            BinASTInterfaceAndField::Directive__RawValue)));
 
   TokenPos pos = tokenizer_->pos(start);
   BINJS_TRY_DECL(result, handler_.newStringLiteral(rawValue, pos));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceDoWhileStatement(
@@ -2685,19 +2689,19 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Test, BinASTField::Body};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   ParseContext::Statement stmt(pc_, StatementKind::DoLoop);
 
-  BINJS_MOZ_TRY_DECL(test,
-                     parseExpression(Context(FieldContext(
-                         BinASTInterfaceAndField::DoWhileStatement__Test))));
+  BINJS_MOZ_TRY_DECL(
+      test, parseExpression(
+                FieldContext(BinASTInterfaceAndField::DoWhileStatement__Test)));
 
   BINJS_MOZ_TRY_DECL(body,
                      parseStatement(Context(FieldContext(
                          BinASTInterfaceAndField::DoWhileStatement__Body))));
 
   BINJS_TRY_DECL(
       result, handler_.newDoWhileStatement(body, test, tokenizer_->pos(start)));
   return result;
@@ -2736,41 +2740,41 @@ BinASTParser<Tok>::parseInterfaceEagerFu
       BinASTField::IsAsync, BinASTField::IsGenerator, BinASTField::Name,
       BinASTField::Length,  BinASTField::Directives,  BinASTField::Contents};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto syntax = FunctionSyntaxKind::Statement;
 
   BINJS_MOZ_TRY_DECL(
       isAsync,
-      tokenizer_->readBool(Context(FieldContext(
-          BinASTInterfaceAndField::EagerFunctionDeclaration__IsAsync))));
+      tokenizer_->readBool(FieldContext(
+          BinASTInterfaceAndField::EagerFunctionDeclaration__IsAsync)));
   if (isAsync) {
     return raiseError(
         "Async function is not supported in this preview release");
   }
   BINJS_MOZ_TRY_DECL(
       isGenerator,
-      tokenizer_->readBool(Context(FieldContext(
-          BinASTInterfaceAndField::EagerFunctionDeclaration__IsGenerator))));
+      tokenizer_->readBool(FieldContext(
+          BinASTInterfaceAndField::EagerFunctionDeclaration__IsGenerator)));
   if (isGenerator) {
     return raiseError("Generator is not supported in this preview release");
   }
   BINJS_MOZ_TRY_DECL(
       name, parseBindingIdentifier(Context(FieldContext(
                 BinASTInterfaceAndField::EagerFunctionDeclaration__Name))));
 
   BINJS_MOZ_TRY_DECL(
-      length, tokenizer_->readUnsignedLong(Context(FieldContext(
-                  BinASTInterfaceAndField::EagerFunctionDeclaration__Length))));
+      length, tokenizer_->readUnsignedLong(FieldContext(
+                  BinASTInterfaceAndField::EagerFunctionDeclaration__Length)));
 
   BINJS_MOZ_TRY_DECL(
       directives,
-      parseListOfDirective(Context(FieldContext(
-          BinASTInterfaceAndField::EagerFunctionDeclaration__Directives))));
+      parseListOfDirective(FieldContext(
+          BinASTInterfaceAndField::EagerFunctionDeclaration__Directives)));
 
   BINJS_MOZ_TRY_DECL(funbox,
                      buildFunctionBox(isGenerator ? GeneratorKind::Generator
                                                   : GeneratorKind::NotGenerator,
                                       isAsync ? FunctionAsyncKind::AsyncFunction
                                               : FunctionAsyncKind::SyncFunction,
                                       syntax,
                                       (syntax != FunctionSyntaxKind::Setter &&
@@ -2818,42 +2822,41 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   const BinASTField expected_fields[6] = {
       BinASTField::IsAsync, BinASTField::IsGenerator, BinASTField::Name,
       BinASTField::Length,  BinASTField::Directives,  BinASTField::Contents};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto syntax = FunctionSyntaxKind::Expression;
 
   BINJS_MOZ_TRY_DECL(
-      isAsync,
-      tokenizer_->readBool(Context(FieldContext(
-          BinASTInterfaceAndField::EagerFunctionExpression__IsAsync))));
+      isAsync, tokenizer_->readBool(FieldContext(
+                   BinASTInterfaceAndField::EagerFunctionExpression__IsAsync)));
   if (isAsync) {
     return raiseError(
         "Async function is not supported in this preview release");
   }
   BINJS_MOZ_TRY_DECL(
       isGenerator,
-      tokenizer_->readBool(Context(FieldContext(
-          BinASTInterfaceAndField::EagerFunctionExpression__IsGenerator))));
+      tokenizer_->readBool(FieldContext(
+          BinASTInterfaceAndField::EagerFunctionExpression__IsGenerator)));
   if (isGenerator) {
     return raiseError("Generator is not supported in this preview release");
   }
   BINJS_MOZ_TRY_DECL(
-      name, parseOptionalBindingIdentifier(Context(FieldContext(
-                BinASTInterfaceAndField::EagerFunctionExpression__Name))));
+      name, parseOptionalBindingIdentifier(FieldContext(
+                BinASTInterfaceAndField::EagerFunctionExpression__Name)));
 
   BINJS_MOZ_TRY_DECL(
-      length, tokenizer_->readUnsignedLong(Context(FieldContext(
-                  BinASTInterfaceAndField::EagerFunctionExpression__Length))));
+      length, tokenizer_->readUnsignedLong(FieldContext(
+                  BinASTInterfaceAndField::EagerFunctionExpression__Length)));
 
   BINJS_MOZ_TRY_DECL(
       directives,
-      parseListOfDirective(Context(FieldContext(
-          BinASTInterfaceAndField::EagerFunctionExpression__Directives))));
+      parseListOfDirective(FieldContext(
+          BinASTInterfaceAndField::EagerFunctionExpression__Directives)));
 
   BINJS_MOZ_TRY_DECL(funbox,
                      buildFunctionBox(isGenerator ? GeneratorKind::Generator
                                                   : GeneratorKind::NotGenerator,
                                       isAsync ? FunctionAsyncKind::AsyncFunction
                                               : FunctionAsyncKind::SyncFunction,
                                       syntax,
                                       (syntax != FunctionSyntaxKind::Setter &&
@@ -2888,37 +2891,37 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   MOZ_TRY(setFunctionParametersAndBody(result, params, bodyScope));
   MOZ_TRY(finishEagerFunction(funbox, nargs));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEagerGetter(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const ListContext& context) {
   MOZ_ASSERT(kind == BinASTKind::EagerGetter);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {
       BinASTField::Name, BinASTField::Directives, BinASTField::Contents};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto syntax = FunctionSyntaxKind::Setter;
   const bool isGenerator = false;
   const bool isAsync = false;
   const auto accessorType = AccessorType::Getter;
   const uint32_t length = 0;
 
-  BINJS_MOZ_TRY_DECL(name, parsePropertyName(Context(FieldContext(
-                               BinASTInterfaceAndField::EagerGetter__Name))));
+  BINJS_MOZ_TRY_DECL(name, parsePropertyName(FieldContext(
+                               BinASTInterfaceAndField::EagerGetter__Name)));
 
   BINJS_MOZ_TRY_DECL(directives,
-                     parseListOfDirective(Context(FieldContext(
-                         BinASTInterfaceAndField::EagerGetter__Directives))));
+                     parseListOfDirective(FieldContext(
+                         BinASTInterfaceAndField::EagerGetter__Directives)));
 
   BINJS_MOZ_TRY_DECL(funbox,
                      buildFunctionBox(isGenerator ? GeneratorKind::Generator
                                                   : GeneratorKind::NotGenerator,
                                       isAsync ? FunctionAsyncKind::AsyncFunction
                                               : FunctionAsyncKind::SyncFunction,
                                       syntax,
                                       (syntax != FunctionSyntaxKind::Setter &&
@@ -2936,17 +2939,17 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   MOZ_ASSERT(pc_->isFunctionBox());
 
   ParseContext::Scope lexicalScope(cx_, pc_, usedNames_);
   BINJS_TRY(lexicalScope.init(pc_));
   ListNode* params;
   ListNode* body;
   MOZ_TRY(parseGetterContents(
       length, &params, &body,
-      Context(FieldContext(BinASTInterfaceAndField::EagerGetter__Contents))));
+      FieldContext(BinASTInterfaceAndField::EagerGetter__Contents)));
   MOZ_TRY(prependDirectivesToBody(body, directives));
   uint32_t nargs = params->count();
 
   BINJS_TRY_DECL(lexicalScopeData,
                  NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
   BINJS_TRY_DECL(bodyScope, handler_.newLexicalScope(*lexicalScopeData, body));
   BINJS_MOZ_TRY_DECL(method, makeEmptyFunctionNode(start, kind, funbox));
   MOZ_TRY(setFunctionParametersAndBody(method, params, bodyScope));
@@ -2954,52 +2957,52 @@ JS::Result<ParseNode*> BinASTParser<Tok>
                              name, method, accessorType));
   MOZ_TRY(finishEagerFunction(funbox, nargs));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEagerMethod(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const ListContext& context) {
   MOZ_ASSERT(kind == BinASTKind::EagerMethod);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[6] = {
       BinASTField::IsAsync, BinASTField::IsGenerator, BinASTField::Name,
       BinASTField::Length,  BinASTField::Directives,  BinASTField::Contents};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto syntax = FunctionSyntaxKind::Method;
   const auto accessorType = AccessorType::None;
 
   BINJS_MOZ_TRY_DECL(isAsync,
-                     tokenizer_->readBool(Context(FieldContext(
-                         BinASTInterfaceAndField::EagerMethod__IsAsync))));
+                     tokenizer_->readBool(FieldContext(
+                         BinASTInterfaceAndField::EagerMethod__IsAsync)));
   if (isAsync) {
     return raiseError(
         "Async function is not supported in this preview release");
   }
   BINJS_MOZ_TRY_DECL(isGenerator,
-                     tokenizer_->readBool(Context(FieldContext(
-                         BinASTInterfaceAndField::EagerMethod__IsGenerator))));
+                     tokenizer_->readBool(FieldContext(
+                         BinASTInterfaceAndField::EagerMethod__IsGenerator)));
   if (isGenerator) {
     return raiseError("Generator is not supported in this preview release");
   }
-  BINJS_MOZ_TRY_DECL(name, parsePropertyName(Context(FieldContext(
-                               BinASTInterfaceAndField::EagerMethod__Name))));
+  BINJS_MOZ_TRY_DECL(name, parsePropertyName(FieldContext(
+                               BinASTInterfaceAndField::EagerMethod__Name)));
 
   BINJS_MOZ_TRY_DECL(
-      length, tokenizer_->readUnsignedLong(Context(
-                  FieldContext(BinASTInterfaceAndField::EagerMethod__Length))));
+      length, tokenizer_->readUnsignedLong(
+                  FieldContext(BinASTInterfaceAndField::EagerMethod__Length)));
 
   BINJS_MOZ_TRY_DECL(directives,
-                     parseListOfDirective(Context(FieldContext(
-                         BinASTInterfaceAndField::EagerMethod__Directives))));
+                     parseListOfDirective(FieldContext(
+                         BinASTInterfaceAndField::EagerMethod__Directives)));
 
   BINJS_MOZ_TRY_DECL(funbox,
                      buildFunctionBox(isGenerator ? GeneratorKind::Generator
                                                   : GeneratorKind::NotGenerator,
                                       isAsync ? FunctionAsyncKind::AsyncFunction
                                               : FunctionAsyncKind::SyncFunction,
                                       syntax,
                                       (syntax != FunctionSyntaxKind::Setter &&
@@ -3035,41 +3038,41 @@ JS::Result<ParseNode*> BinASTParser<Tok>
                              name, method, accessorType));
   MOZ_TRY(finishEagerFunction(funbox, nargs));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEagerSetter(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const ListContext& context) {
   MOZ_ASSERT(kind == BinASTKind::EagerSetter);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[4] = {
       BinASTField::Name, BinASTField::Length, BinASTField::Directives,
       BinASTField::Contents};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto syntax = FunctionSyntaxKind::Setter;
   const bool isGenerator = false;
   const bool isAsync = false;
   const auto accessorType = AccessorType::Setter;
 
-  BINJS_MOZ_TRY_DECL(name, parsePropertyName(Context(FieldContext(
-                               BinASTInterfaceAndField::EagerSetter__Name))));
+  BINJS_MOZ_TRY_DECL(name, parsePropertyName(FieldContext(
+                               BinASTInterfaceAndField::EagerSetter__Name)));
 
   BINJS_MOZ_TRY_DECL(
-      length, tokenizer_->readUnsignedLong(Context(
-                  FieldContext(BinASTInterfaceAndField::EagerSetter__Length))));
+      length, tokenizer_->readUnsignedLong(
+                  FieldContext(BinASTInterfaceAndField::EagerSetter__Length)));
 
   BINJS_MOZ_TRY_DECL(directives,
-                     parseListOfDirective(Context(FieldContext(
-                         BinASTInterfaceAndField::EagerSetter__Directives))));
+                     parseListOfDirective(FieldContext(
+                         BinASTInterfaceAndField::EagerSetter__Directives)));
 
   BINJS_MOZ_TRY_DECL(funbox,
                      buildFunctionBox(isGenerator ? GeneratorKind::Generator
                                                   : GeneratorKind::NotGenerator,
                                       isAsync ? FunctionAsyncKind::AsyncFunction
                                               : FunctionAsyncKind::SyncFunction,
                                       syntax,
                                       (syntax != FunctionSyntaxKind::Setter &&
@@ -3087,17 +3090,17 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   MOZ_ASSERT(pc_->isFunctionBox());
 
   ParseContext::Scope lexicalScope(cx_, pc_, usedNames_);
   BINJS_TRY(lexicalScope.init(pc_));
   ListNode* params;
   ListNode* body;
   MOZ_TRY(parseSetterContents(
       length, &params, &body,
-      Context(FieldContext(BinASTInterfaceAndField::EagerSetter__Contents))));
+      FieldContext(BinASTInterfaceAndField::EagerSetter__Contents)));
   MOZ_TRY(prependDirectivesToBody(body, directives));
   uint32_t nargs = params->count();
 
   BINJS_TRY_DECL(lexicalScopeData,
                  NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
   BINJS_TRY_DECL(bodyScope, handler_.newLexicalScope(*lexicalScopeData, body));
   BINJS_MOZ_TRY_DECL(method, makeEmptyFunctionNode(start, kind, funbox));
   MOZ_TRY(setFunctionParametersAndBody(method, params, bodyScope));
@@ -3128,44 +3131,44 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Expression};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   BINJS_MOZ_TRY_DECL(
       expression,
-      parseExpression(Context(FieldContext(
-          BinASTInterfaceAndField::ExpressionStatement__Expression))));
+      parseExpression(FieldContext(
+          BinASTInterfaceAndField::ExpressionStatement__Expression)));
 
   BINJS_TRY_DECL(result, handler_.newExprStatement(expression));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceForInOfBinding(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   MOZ_ASSERT(kind == BinASTKind::ForInOfBinding);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Kind,
                                           BinASTField::Binding};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   AutoVariableDeclarationKind kindGuard(this);
 
   BINJS_MOZ_TRY_DECL(
-      kind_, parseVariableDeclarationKind(Context(
-                 FieldContext(BinASTInterfaceAndField::ForInOfBinding__Kind))));
+      kind_, parseVariableDeclarationKind(
+                 FieldContext(BinASTInterfaceAndField::ForInOfBinding__Kind)));
 
   BINJS_MOZ_TRY_DECL(binding,
-                     parseBinding(Context(FieldContext(
-                         BinASTInterfaceAndField::ForInOfBinding__Binding))));
+                     parseBinding(FieldContext(
+                         BinASTInterfaceAndField::ForInOfBinding__Binding)));
 
   // Restored by `kindGuard`.
   variableDeclarationKind_ = kind_;
   MOZ_TRY(
       checkBinding(binding->template as<NameNode>().atom()->asPropertyName()));
   ParseNodeKind pnk;
   switch (kind_) {
     case VariableDeclarationKind::Var:
@@ -3197,23 +3200,22 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   ParseContext::Statement stmt(pc_, StatementKind::ForInLoop);
 
   // Implicit scope around the `for`, used to store `for (let x in  ...)`
   // or `for (const x in ...)`-style declarations. Detail on the
   // declaration is stored as part of `scope`.
   ParseContext::Scope scope(cx_, pc_, usedNames_);
   BINJS_TRY(scope.init(pc_));
 
+  BINJS_MOZ_TRY_DECL(left, parseAssignmentTargetOrForInOfBinding(FieldContext(
+                               BinASTInterfaceAndField::ForInStatement__Left)));
+
   BINJS_MOZ_TRY_DECL(
-      left, parseAssignmentTargetOrForInOfBinding(Context(
-                FieldContext(BinASTInterfaceAndField::ForInStatement__Left))));
-
-  BINJS_MOZ_TRY_DECL(right,
-                     parseExpression(Context(FieldContext(
-                         BinASTInterfaceAndField::ForInStatement__Right))));
+      right, parseExpression(
+                 FieldContext(BinASTInterfaceAndField::ForInStatement__Right)));
 
   BINJS_MOZ_TRY_DECL(
       body, parseStatement(Context(
                 FieldContext(BinASTInterfaceAndField::ForInStatement__Body))));
 
   BINJS_TRY_DECL(forHead,
                  handler_.newForInOrOfHead(ParseNodeKind::ForIn, left, right,
                                            tokenizer_->pos(start)));
@@ -3253,25 +3255,25 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 
   // Implicit scope around the `for`, used to store `for (let x; ...; ...)`
   // or `for (const x; ...; ...)`-style declarations. Detail on the
   // declaration is stored as part of `BINJS_Scope`.
   ParseContext::Scope scope(cx_, pc_, usedNames_);
   BINJS_TRY(scope.init(pc_));
 
   BINJS_MOZ_TRY_DECL(
-      init, parseOptionalExpressionOrVariableDeclaration(Context(
-                FieldContext(BinASTInterfaceAndField::ForStatement__Init))));
-
-  BINJS_MOZ_TRY_DECL(test, parseOptionalExpression(Context(FieldContext(
-                               BinASTInterfaceAndField::ForStatement__Test))));
-
-  BINJS_MOZ_TRY_DECL(update,
-                     parseOptionalExpression(Context(FieldContext(
-                         BinASTInterfaceAndField::ForStatement__Update))));
+      init, parseOptionalExpressionOrVariableDeclaration(
+                FieldContext(BinASTInterfaceAndField::ForStatement__Init)));
+
+  BINJS_MOZ_TRY_DECL(test, parseOptionalExpression(FieldContext(
+                               BinASTInterfaceAndField::ForStatement__Test)));
+
+  BINJS_MOZ_TRY_DECL(
+      update, parseOptionalExpression(
+                  FieldContext(BinASTInterfaceAndField::ForStatement__Update)));
 
   BINJS_MOZ_TRY_DECL(body, parseStatement(Context(FieldContext(
                                BinASTInterfaceAndField::ForStatement__Body))));
 
   BINJS_TRY_DECL(
       forHead, handler_.newForHead(init, test, update, tokenizer_->pos(start)));
   ParseNode* result;
   BINJS_TRY_VAR(result, handler_.newForStatement(start, forHead, body,
@@ -3287,17 +3289,17 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 /*
  interface FormalParameters : Node {
     FrozenArray<Parameter> items;
     Binding? rest;
  }
 */
 template <typename Tok>
 JS::Result<ListNode*> BinASTParser<Tok>::parseFormalParameters(
-    const Context& context) {
+    const FieldContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::FormalParameters) {
     return raiseInvalidKind("FormalParameters", kind);
   }
@@ -3307,33 +3309,33 @@ JS::Result<ListNode*> BinASTParser<Tok>:
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<ListNode*> BinASTParser<Tok>::parseInterfaceFormalParameters(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   MOZ_ASSERT(kind == BinASTKind::FormalParameters);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Items,
                                           BinASTField::Rest};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   BINJS_MOZ_TRY_DECL(items,
-                     parseListOfParameter(Context(FieldContext(
-                         BinASTInterfaceAndField::FormalParameters__Items))));
-
-  BINJS_MOZ_TRY_DECL(rest,
-                     parseOptionalBinding(Context(FieldContext(
-                         BinASTInterfaceAndField::FormalParameters__Rest))));
+                     parseListOfParameter(FieldContext(
+                         BinASTInterfaceAndField::FormalParameters__Items)));
+
+  BINJS_MOZ_TRY_DECL(
+      rest, parseOptionalBinding(
+                FieldContext(BinASTInterfaceAndField::FormalParameters__Rest)));
 
   auto result = items;
   if (rest) {
     return raiseError(
         "Rest parameter is not supported in this preview release");
   }
   return result;
 }
@@ -3384,49 +3386,49 @@ JS::Result<Ok> BinASTParser<Tok>::parseI
                                           BinASTField::Params,
                                           BinASTField::BodyScope,
                                           BinASTField::Body};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   BINJS_MOZ_TRY_DECL(
       isFunctionNameCaptured,
-      tokenizer_->readBool(Context(FieldContext(
+      tokenizer_->readBool(FieldContext(
           BinASTInterfaceAndField::
-              FunctionExpressionContents__IsFunctionNameCaptured))));
+              FunctionExpressionContents__IsFunctionNameCaptured)));
   // Per spec, isFunctionNameCaptured can be true for anonymous
   // function.  Check isFunctionNameCaptured only for named
   // function.
   if (pc_->functionBox()->isNamedLambda() && isFunctionNameCaptured) {
     captureFunctionName();
   }
   BINJS_MOZ_TRY_DECL(isThisCaptured,
-                     tokenizer_->readBool(Context(FieldContext(
+                     tokenizer_->readBool(FieldContext(
                          BinASTInterfaceAndField::
-                             FunctionExpressionContents__IsThisCaptured))));
+                             FunctionExpressionContents__IsThisCaptured)));
   // TODO: Use this in BinASTParser::buildFunction.
   (void)isThisCaptured;
   Rooted<GCVector<JSAtom*>> positionalParams(cx_, GCVector<JSAtom*>(cx_));
   MOZ_TRY(parseAssertedParameterScope(
       &positionalParams,
-      Context(FieldContext(BinASTInterfaceAndField::
-                               FunctionExpressionContents__ParameterScope))));
+      FieldContext(BinASTInterfaceAndField::
+                       FunctionExpressionContents__ParameterScope)));
 
   BINJS_MOZ_TRY_DECL(
       params,
-      parseFormalParameters(Context(FieldContext(
-          BinASTInterfaceAndField::FunctionExpressionContents__Params))));
+      parseFormalParameters(FieldContext(
+          BinASTInterfaceAndField::FunctionExpressionContents__Params)));
   MOZ_TRY(checkFunctionLength(funLength));
   MOZ_TRY(checkPositionalParameterIndices(positionalParams, params));
-  MOZ_TRY(parseAssertedVarScope(Context(FieldContext(
-      BinASTInterfaceAndField::FunctionExpressionContents__BodyScope))));
+  MOZ_TRY(parseAssertedVarScope(FieldContext(
+      BinASTInterfaceAndField::FunctionExpressionContents__BodyScope)));
 
   BINJS_MOZ_TRY_DECL(
-      body, parseFunctionBody(Context(FieldContext(
-                BinASTInterfaceAndField::FunctionExpressionContents__Body))));
+      body, parseFunctionBody(FieldContext(
+                BinASTInterfaceAndField::FunctionExpressionContents__Body)));
 
   *paramsOut = params;
   *bodyOut = body;
   auto result = Ok();
   return result;
 }
 
 /*
@@ -3471,56 +3473,55 @@ JS::Result<Ok> BinASTParser<Tok>::parseI
   const BinASTField expected_fields[5] = {
       BinASTField::IsThisCaptured, BinASTField::ParameterScope,
       BinASTField::Params, BinASTField::BodyScope, BinASTField::Body};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   BINJS_MOZ_TRY_DECL(
       isThisCaptured,
-      tokenizer_->readBool(Context(FieldContext(
-          BinASTInterfaceAndField::FunctionOrMethodContents__IsThisCaptured))));
+      tokenizer_->readBool(FieldContext(
+          BinASTInterfaceAndField::FunctionOrMethodContents__IsThisCaptured)));
   // TODO: Use this in BinASTParser::buildFunction.
   (void)isThisCaptured;
   Rooted<GCVector<JSAtom*>> positionalParams(cx_, GCVector<JSAtom*>(cx_));
   MOZ_TRY(parseAssertedParameterScope(
       &positionalParams,
-      Context(FieldContext(
-          BinASTInterfaceAndField::FunctionOrMethodContents__ParameterScope))));
+      FieldContext(
+          BinASTInterfaceAndField::FunctionOrMethodContents__ParameterScope)));
 
   BINJS_MOZ_TRY_DECL(
-      params, parseFormalParameters(Context(FieldContext(
-                  BinASTInterfaceAndField::FunctionOrMethodContents__Params))));
+      params, parseFormalParameters(FieldContext(
+                  BinASTInterfaceAndField::FunctionOrMethodContents__Params)));
   MOZ_TRY(checkFunctionLength(funLength));
   MOZ_TRY(checkPositionalParameterIndices(positionalParams, params));
-  MOZ_TRY(parseAssertedVarScope(Context(FieldContext(
-      BinASTInterfaceAndField::FunctionOrMethodContents__BodyScope))));
+  MOZ_TRY(parseAssertedVarScope(FieldContext(
+      BinASTInterfaceAndField::FunctionOrMethodContents__BodyScope)));
 
   BINJS_MOZ_TRY_DECL(
-      body, parseFunctionBody(Context(FieldContext(
-                BinASTInterfaceAndField::FunctionOrMethodContents__Body))));
+      body, parseFunctionBody(FieldContext(
+                BinASTInterfaceAndField::FunctionOrMethodContents__Body)));
 
   *paramsOut = params;
   *bodyOut = body;
   auto result = Ok();
   return result;
 }
 
 /*
  interface GetterContents : Node {
     bool isThisCaptured;
     AssertedVarScope bodyScope;
     FunctionBody body;
  }
 */
 template <typename Tok>
-JS::Result<Ok> BinASTParser<Tok>::parseGetterContents(uint32_t funLength,
-                                                      ListNode** paramsOut,
-                                                      ListNode** bodyOut,
-                                                      const Context& context) {
+JS::Result<Ok> BinASTParser<Tok>::parseGetterContents(
+    uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut,
+    const FieldContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::GetterContents) {
     return raiseInvalidKind("GetterContents", kind);
   }
@@ -3532,39 +3533,38 @@ JS::Result<Ok> BinASTParser<Tok>::parseG
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseInterfaceGetterContents(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
     uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut,
-    const Context& context) {
+    const FieldContext& context) {
   MOZ_ASSERT(kind == BinASTKind::GetterContents);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {
       BinASTField::IsThisCaptured, BinASTField::BodyScope, BinASTField::Body};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   BINJS_MOZ_TRY_DECL(
       isThisCaptured,
-      tokenizer_->readBool(Context(FieldContext(
-          BinASTInterfaceAndField::GetterContents__IsThisCaptured))));
+      tokenizer_->readBool(FieldContext(
+          BinASTInterfaceAndField::GetterContents__IsThisCaptured)));
   // TODO: Use this in BinASTParser::buildFunction.
   (void)isThisCaptured;
-  MOZ_TRY(parseAssertedVarScope(Context(
-      FieldContext(BinASTInterfaceAndField::GetterContents__BodyScope))));
+  MOZ_TRY(parseAssertedVarScope(
+      FieldContext(BinASTInterfaceAndField::GetterContents__BodyScope)));
 
   BINJS_TRY_DECL(params, handler_.newParamsBody(tokenizer_->pos(start)));
-  BINJS_MOZ_TRY_DECL(
-      body, parseFunctionBody(Context(
-                FieldContext(BinASTInterfaceAndField::GetterContents__Body))));
+  BINJS_MOZ_TRY_DECL(body, parseFunctionBody(FieldContext(
+                               BinASTInterfaceAndField::GetterContents__Body)));
 
   *paramsOut = params;
   *bodyOut = body;
   auto result = Ok();
   return result;
 }
 
 /*
@@ -3599,18 +3599,18 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Name};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   RootedAtom name(cx_);
-  MOZ_TRY_VAR(name, tokenizer_->readIdentifierName(Context(FieldContext(
-                        BinASTInterfaceAndField::IdentifierExpression__Name))));
+  MOZ_TRY_VAR(name, tokenizer_->readIdentifierName(FieldContext(
+                        BinASTInterfaceAndField::IdentifierExpression__Name)));
 
   BINJS_TRY(usedNames_.noteUse(cx_, name, pc_->scriptId(),
                                pc_->innermostScope()->id()));
   BINJS_TRY_DECL(result, handler_.newName(name->asPropertyName(),
                                           tokenizer_->pos(start), cx_));
   return result;
 }
 
@@ -3622,26 +3622,26 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {
       BinASTField::Test, BinASTField::Consequent, BinASTField::Alternate};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(test, parseExpression(Context(FieldContext(
-                               BinASTInterfaceAndField::IfStatement__Test))));
+  BINJS_MOZ_TRY_DECL(test, parseExpression(FieldContext(
+                               BinASTInterfaceAndField::IfStatement__Test)));
 
   BINJS_MOZ_TRY_DECL(consequent,
                      parseStatement(Context(FieldContext(
                          BinASTInterfaceAndField::IfStatement__Consequent))));
 
   BINJS_MOZ_TRY_DECL(alternate,
-                     parseOptionalStatement(Context(FieldContext(
-                         BinASTInterfaceAndField::IfStatement__Alternate))));
+                     parseOptionalStatement(FieldContext(
+                         BinASTInterfaceAndField::IfStatement__Alternate)));
 
   BINJS_TRY_DECL(result,
                  handler_.newIfStatement(start, test, consequent, alternate));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLabelledStatement(
@@ -3652,18 +3652,18 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Label,
                                           BinASTField::Body};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   RootedAtom label(cx_);
-  MOZ_TRY_VAR(label, tokenizer_->readAtom(Context(FieldContext(
-                         BinASTInterfaceAndField::LabelledStatement__Label))));
+  MOZ_TRY_VAR(label, tokenizer_->readAtom(FieldContext(
+                         BinASTInterfaceAndField::LabelledStatement__Label)));
   if (!IsIdentifier(label)) {
     return raiseError("Invalid identifier");
   }
   ParseContext::LabelStatement stmt(pc_, label);
   BINJS_MOZ_TRY_DECL(body,
                      parseStatement(Context(FieldContext(
                          BinASTInterfaceAndField::LabelledStatement__Body))));
 
@@ -3704,47 +3704,46 @@ JS::Result<ParseNode*> BinASTParser<Tok>
       BinASTField::IsAsync, BinASTField::IsGenerator, BinASTField::Name,
       BinASTField::Length,  BinASTField::Directives,  BinASTField::ContentsSkip,
       BinASTField::Contents};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto syntax = FunctionSyntaxKind::Statement;
 
   BINJS_MOZ_TRY_DECL(
-      isAsync,
-      tokenizer_->readBool(Context(FieldContext(
-          BinASTInterfaceAndField::LazyFunctionDeclaration__IsAsync))));
+      isAsync, tokenizer_->readBool(FieldContext(
+                   BinASTInterfaceAndField::LazyFunctionDeclaration__IsAsync)));
   if (isAsync) {
     return raiseError(
         "Async function is not supported in this preview release");
   }
   BINJS_MOZ_TRY_DECL(
       isGenerator,
-      tokenizer_->readBool(Context(FieldContext(
-          BinASTInterfaceAndField::LazyFunctionDeclaration__IsGenerator))));
+      tokenizer_->readBool(FieldContext(
+          BinASTInterfaceAndField::LazyFunctionDeclaration__IsGenerator)));
   if (isGenerator) {
     return raiseError("Generator is not supported in this preview release");
   }
   BINJS_MOZ_TRY_DECL(
       name, parseBindingIdentifier(Context(FieldContext(
                 BinASTInterfaceAndField::LazyFunctionDeclaration__Name))));
 
   BINJS_MOZ_TRY_DECL(
-      length, tokenizer_->readUnsignedLong(Context(FieldContext(
-                  BinASTInterfaceAndField::LazyFunctionDeclaration__Length))));
+      length, tokenizer_->readUnsignedLong(FieldContext(
+                  BinASTInterfaceAndField::LazyFunctionDeclaration__Length)));
 
   BINJS_MOZ_TRY_DECL(
       directives,
-      parseListOfDirective(Context(FieldContext(
-          BinASTInterfaceAndField::LazyFunctionDeclaration__Directives))));
+      parseListOfDirective(FieldContext(
+          BinASTInterfaceAndField::LazyFunctionDeclaration__Directives)));
 
   BINJS_MOZ_TRY_DECL(
       contentsSkip,
-      tokenizer_->readSkippableSubTree(Context(FieldContext(
-          BinASTInterfaceAndField::LazyFunctionDeclaration__ContentsSkip))));
+      tokenizer_->readSkippableSubTree(FieldContext(
+          BinASTInterfaceAndField::LazyFunctionDeclaration__ContentsSkip)));
   // Don't parse the contents until we delazify.
 
   // TODO: This will become incorrect in the face of ES6 features.
   uint32_t nargs = length;
 
   BINJS_MOZ_TRY_DECL(funbox,
                      buildFunctionBox(isGenerator ? GeneratorKind::Generator
                                                   : GeneratorKind::NotGenerator,
@@ -3774,46 +3773,46 @@ JS::Result<ParseNode*> BinASTParser<Tok>
       BinASTField::IsAsync, BinASTField::IsGenerator, BinASTField::Name,
       BinASTField::Length,  BinASTField::Directives,  BinASTField::ContentsSkip,
       BinASTField::Contents};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   const auto syntax = FunctionSyntaxKind::Expression;
 
   BINJS_MOZ_TRY_DECL(
-      isAsync, tokenizer_->readBool(Context(FieldContext(
-                   BinASTInterfaceAndField::LazyFunctionExpression__IsAsync))));
+      isAsync, tokenizer_->readBool(FieldContext(
+                   BinASTInterfaceAndField::LazyFunctionExpression__IsAsync)));
   if (isAsync) {
     return raiseError(
         "Async function is not supported in this preview release");
   }
   BINJS_MOZ_TRY_DECL(
       isGenerator,
-      tokenizer_->readBool(Context(FieldContext(
-          BinASTInterfaceAndField::LazyFunctionExpression__IsGenerator))));
+      tokenizer_->readBool(FieldContext(
+          BinASTInterfaceAndField::LazyFunctionExpression__IsGenerator)));
   if (isGenerator) {
     return raiseError("Generator is not supported in this preview release");
   }
   BINJS_MOZ_TRY_DECL(
-      name, parseOptionalBindingIdentifier(Context(FieldContext(
-                BinASTInterfaceAndField::LazyFunctionExpression__Name))));
+      name, parseOptionalBindingIdentifier(FieldContext(
+                BinASTInterfaceAndField::LazyFunctionExpression__Name)));
 
   BINJS_MOZ_TRY_DECL(
-      length, tokenizer_->readUnsignedLong(Context(FieldContext(
-                  BinASTInterfaceAndField::LazyFunctionExpression__Length))));
+      length, tokenizer_->readUnsignedLong(FieldContext(
+                  BinASTInterfaceAndField::LazyFunctionExpression__Length)));
 
   BINJS_MOZ_TRY_DECL(
       directives,
-      parseListOfDirective(Context(FieldContext(
-          BinASTInterfaceAndField::LazyFunctionExpression__Directives))));
+      parseListOfDirective(FieldContext(
+          BinASTInterfaceAndField::LazyFunctionExpression__Directives)));
 
   BINJS_MOZ_TRY_DECL(
       contentsSkip,
-      tokenizer_->readSkippableSubTree(Context(FieldContext(
-          BinASTInterfaceAndField::LazyFunctionExpression__ContentsSkip))));
+      tokenizer_->readSkippableSubTree(FieldContext(
+          BinASTInterfaceAndField::LazyFunctionExpression__ContentsSkip)));
   // Don't parse the contents until we delazify.
 
   // TODO: This will become incorrect in the face of ES6 features.
   uint32_t nargs = length;
 
   BINJS_MOZ_TRY_DECL(funbox,
                      buildFunctionBox(isGenerator ? GeneratorKind::Generator
                                                   : GeneratorKind::NotGenerator,
@@ -3829,33 +3828,33 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   auto skipEnd = skipStart + contentsSkip.length();
   MOZ_TRY(finishLazyFunction(funbox, nargs, skipStart, skipEnd));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLazyGetter(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const ListContext& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release (LazyGetter)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLazyMethod(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const ListContext& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release (LazyMethod)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLazySetter(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const ListContext& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release (LazySetter)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceLiteralBooleanExpression(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
@@ -3864,18 +3863,18 @@ BinASTParser<Tok>::parseInterfaceLiteral
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Value};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   BINJS_MOZ_TRY_DECL(
-      value, tokenizer_->readBool(Context(FieldContext(
-                 BinASTInterfaceAndField::LiteralBooleanExpression__Value))));
+      value, tokenizer_->readBool(FieldContext(
+                 BinASTInterfaceAndField::LiteralBooleanExpression__Value)));
 
   BINJS_TRY_DECL(result,
                  handler_.newBooleanLiteral(value, tokenizer_->pos(start)));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
@@ -3908,40 +3907,39 @@ BinASTParser<Tok>::parseInterfaceLiteral
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Value};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   BINJS_MOZ_TRY_DECL(
-      value, tokenizer_->readDouble(Context(FieldContext(
-                 BinASTInterfaceAndField::LiteralNumericExpression__Value))));
+      value, tokenizer_->readDouble(FieldContext(
+                 BinASTInterfaceAndField::LiteralNumericExpression__Value)));
 
   BINJS_TRY_DECL(result, handler_.newNumber(value, DecimalPoint::HasDecimal,
                                             tokenizer_->pos(start)));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceLiteralPropertyName(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   MOZ_ASSERT(kind == BinASTKind::LiteralPropertyName);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Value};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   RootedAtom value(cx_);
-  MOZ_TRY_VAR(value,
-              tokenizer_->readAtom(Context(FieldContext(
-                  BinASTInterfaceAndField::LiteralPropertyName__Value))));
+  MOZ_TRY_VAR(value, tokenizer_->readAtom(FieldContext(
+                         BinASTInterfaceAndField::LiteralPropertyName__Value)));
 
   ParseNode* result;
   uint32_t index;
   if (value->isIndex(&index)) {
     BINJS_TRY_VAR(result,
                   handler_.newNumber(index, NoDecimal,
                                      TokenPos(start, tokenizer_->offset())));
   } else {
@@ -3961,21 +3959,21 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Pattern,
                                           BinASTField::Flags};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   RootedAtom pattern(cx_);
   MOZ_TRY_VAR(pattern,
-              tokenizer_->readAtom(Context(FieldContext(
-                  BinASTInterfaceAndField::LiteralRegExpExpression__Pattern))));
+              tokenizer_->readAtom(FieldContext(
+                  BinASTInterfaceAndField::LiteralRegExpExpression__Pattern)));
   RegExpFlags reflags = JS::RegExpFlag::NoFlags;
-  auto flagsContext = Context(
-      FieldContext(BinASTInterfaceAndField::LiteralRegExpExpression__Flags));
+  auto flagsContext =
+      FieldContext(BinASTInterfaceAndField::LiteralRegExpExpression__Flags);
   if (mozilla::IsSame<Tok, BinASTTokenReaderContext>::value) {
     // Hack: optimized `readChars` is not implemented for
     // `BinASTTokenReaderContext`.
     RootedAtom flags(cx_);
     MOZ_TRY_VAR(flags, tokenizer_->readAtom(flagsContext));
     if (!this->parseRegExpFlags(flags, &reflags)) {
       return raiseError("Invalid regexp flags");
     }
@@ -4005,28 +4003,28 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Value};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   RootedAtom value(cx_);
   MOZ_TRY_VAR(value,
-              tokenizer_->readAtom(Context(FieldContext(
-                  BinASTInterfaceAndField::LiteralStringExpression__Value))));
+              tokenizer_->readAtom(FieldContext(
+                  BinASTInterfaceAndField::LiteralStringExpression__Value)));
 
   BINJS_TRY_DECL(result,
                  handler_.newStringLiteral(value, tokenizer_->pos(start)));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceModule(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const RootContext& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release (Module)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceNewExpression(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
     const Context& context) {
@@ -4035,22 +4033,22 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Callee,
                                           BinASTField::Arguments};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   BINJS_MOZ_TRY_DECL(callee,
-                     parseExpression(Context(FieldContext(
-                         BinASTInterfaceAndField::NewExpression__Callee))));
+                     parseExpression(FieldContext(
+                         BinASTInterfaceAndField::NewExpression__Callee)));
 
   BINJS_MOZ_TRY_DECL(arguments,
-                     parseArguments(Context(FieldContext(
-                         BinASTInterfaceAndField::NewExpression__Arguments))));
+                     parseArguments(FieldContext(
+                         BinASTInterfaceAndField::NewExpression__Arguments)));
 
   BINJS_TRY_DECL(result,
                  handler_.newNewExpression(tokenizer_->pos(start).begin, callee,
                                            arguments, /* isSpread = */ false));
   return result;
 }
 
 template <typename Tok>
@@ -4060,17 +4058,17 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   return raiseError(
       "FIXME: Not implemented yet in this preview release "
       "(NewTargetExpression)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceObjectAssignmentTarget(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release "
       "(ObjectAssignmentTarget)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceObjectBinding(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
@@ -4087,18 +4085,18 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Properties};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   BINJS_MOZ_TRY_DECL(
-      properties, parseListOfObjectProperty(Context(FieldContext(
-                      BinASTInterfaceAndField::ObjectExpression__Properties))));
+      properties, parseListOfObjectProperty(FieldContext(
+                      BinASTInterfaceAndField::ObjectExpression__Properties)));
 
   auto result = properties;
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceReturnStatement(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
@@ -4113,47 +4111,47 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   if (!pc_->isFunctionBox()) {
     // Return statements are permitted only inside functions.
     return raiseInvalidKind("Toplevel Statement", kind);
   }
 
   pc_->functionBox()->usesReturn = true;
 
   BINJS_MOZ_TRY_DECL(
-      expression, parseOptionalExpression(Context(FieldContext(
-                      BinASTInterfaceAndField::ReturnStatement__Expression))));
+      expression, parseOptionalExpression(FieldContext(
+                      BinASTInterfaceAndField::ReturnStatement__Expression)));
 
   BINJS_TRY_DECL(
       result, handler_.newReturnStatement(expression, tokenizer_->pos(start)));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceScript(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const RootContext& context) {
   MOZ_ASSERT(kind == BinASTKind::Script);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {
       BinASTField::Scope, BinASTField::Directives, BinASTField::Statements};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   MOZ_TRY(parseAssertedScriptGlobalScope(
-      Context(FieldContext(BinASTInterfaceAndField::Script__Scope))));
+      FieldContext(BinASTInterfaceAndField::Script__Scope)));
 
   BINJS_MOZ_TRY_DECL(directives,
-                     parseListOfDirective(Context(FieldContext(
-                         BinASTInterfaceAndField::Script__Directives))));
+                     parseListOfDirective(FieldContext(
+                         BinASTInterfaceAndField::Script__Directives)));
   forceStrictIfNecessary(pc_->sc(), directives);
   BINJS_MOZ_TRY_DECL(statements,
-                     parseListOfStatement(Context(FieldContext(
-                         BinASTInterfaceAndField::Script__Statements))));
+                     parseListOfStatement(FieldContext(
+                         BinASTInterfaceAndField::Script__Statements)));
 
   MOZ_TRY(checkClosedVars(pc_->varScope()));
   MOZ_TRY(prependDirectivesToBody(/* body = */ statements, directives));
   auto result = statements;
   return result;
 }
 
 /*
@@ -4161,20 +4159,19 @@ JS::Result<ParseNode*> BinASTParser<Tok>
     bool isThisCaptured;
     AssertedParameterScope parameterScope;
     Parameter param;
     AssertedVarScope bodyScope;
     FunctionBody body;
  }
 */
 template <typename Tok>
-JS::Result<Ok> BinASTParser<Tok>::parseSetterContents(uint32_t funLength,
-                                                      ListNode** paramsOut,
-                                                      ListNode** bodyOut,
-                                                      const Context& context) {
+JS::Result<Ok> BinASTParser<Tok>::parseSetterContents(
+    uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut,
+    const FieldContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::SetterContents) {
     return raiseInvalidKind("SetterContents", kind);
   }
@@ -4186,62 +4183,60 @@ JS::Result<Ok> BinASTParser<Tok>::parseS
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseInterfaceSetterContents(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
     uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut,
-    const Context& context) {
+    const FieldContext& context) {
   MOZ_ASSERT(kind == BinASTKind::SetterContents);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[5] = {
       BinASTField::IsThisCaptured, BinASTField::ParameterScope,
       BinASTField::Param, BinASTField::BodyScope, BinASTField::Body};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   BINJS_MOZ_TRY_DECL(
       isThisCaptured,
-      tokenizer_->readBool(Context(FieldContext(
-          BinASTInterfaceAndField::SetterContents__IsThisCaptured))));
+      tokenizer_->readBool(FieldContext(
+          BinASTInterfaceAndField::SetterContents__IsThisCaptured)));
   // TODO: Use this in BinASTParser::buildFunction.
   (void)isThisCaptured;
   Rooted<GCVector<JSAtom*>> positionalParams(cx_, GCVector<JSAtom*>(cx_));
   MOZ_TRY(parseAssertedParameterScope(
       &positionalParams,
-      Context(FieldContext(
-          BinASTInterfaceAndField::SetterContents__ParameterScope))));
+      FieldContext(BinASTInterfaceAndField::SetterContents__ParameterScope)));
 
   BINJS_MOZ_TRY_DECL(param,
                      parseParameter(Context(FieldContext(
                          BinASTInterfaceAndField::SetterContents__Param))));
   BINJS_TRY_DECL(params, handler_.newParamsBody(param->pn_pos));
   handler_.addList(params, param);
   MOZ_TRY(checkPositionalParameterIndices(positionalParams, params));
-  MOZ_TRY(parseAssertedVarScope(Context(
-      FieldContext(BinASTInterfaceAndField::SetterContents__BodyScope))));
-
-  BINJS_MOZ_TRY_DECL(
-      body, parseFunctionBody(Context(
-                FieldContext(BinASTInterfaceAndField::SetterContents__Body))));
+  MOZ_TRY(parseAssertedVarScope(
+      FieldContext(BinASTInterfaceAndField::SetterContents__BodyScope)));
+
+  BINJS_MOZ_TRY_DECL(body, parseFunctionBody(FieldContext(
+                               BinASTInterfaceAndField::SetterContents__Body)));
 
   *paramsOut = params;
   *bodyOut = body;
   auto result = Ok();
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceShorthandProperty(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const ListContext& context) {
   MOZ_ASSERT(kind == BinASTKind::ShorthandProperty);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Name};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
@@ -4258,48 +4253,48 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   BINJS_TRY_DECL(result,
                  handler_.newShorthandPropertyDefinition(propName, name));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceSpreadElement(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const ListContext& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release (SpreadElement)");
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseInterfaceStaticMemberAssignmentTarget(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   MOZ_ASSERT(kind == BinASTKind::StaticMemberAssignmentTarget);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Object,
                                           BinASTField::Property};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   size_t nameStart;
 
   BINJS_MOZ_TRY_DECL(
       object,
-      parseExpressionOrSuper(Context(FieldContext(
-          BinASTInterfaceAndField::StaticMemberAssignmentTarget__Object))));
+      parseExpressionOrSuper(FieldContext(
+          BinASTInterfaceAndField::StaticMemberAssignmentTarget__Object)));
 
   RootedAtom property(cx_);
   {
     nameStart = tokenizer_->offset();
     MOZ_TRY_VAR(
         property,
-        tokenizer_->readPropertyKey(Context(FieldContext(
-            BinASTInterfaceAndField::StaticMemberAssignmentTarget__Property))));
+        tokenizer_->readPropertyKey(FieldContext(
+            BinASTInterfaceAndField::StaticMemberAssignmentTarget__Property)));
   }
 
   BINJS_TRY_DECL(name, handler_.newPropertyName(property->asPropertyName(),
                                                 tokenizer_->pos(nameStart)));
   BINJS_TRY_DECL(result, handler_.newPropertyAccess(object, name));
   return result;
 }
 
@@ -4313,51 +4308,51 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Object,
                                           BinASTField::Property};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   size_t nameStart;
 
   BINJS_MOZ_TRY_DECL(
-      object, parseExpressionOrSuper(Context(FieldContext(
-                  BinASTInterfaceAndField::StaticMemberExpression__Object))));
+      object, parseExpressionOrSuper(FieldContext(
+                  BinASTInterfaceAndField::StaticMemberExpression__Object)));
 
   RootedAtom property(cx_);
   {
     nameStart = tokenizer_->offset();
     MOZ_TRY_VAR(
         property,
-        tokenizer_->readPropertyKey(Context(FieldContext(
-            BinASTInterfaceAndField::StaticMemberExpression__Property))));
+        tokenizer_->readPropertyKey(FieldContext(
+            BinASTInterfaceAndField::StaticMemberExpression__Property)));
   }
 
   BINJS_TRY_DECL(name, handler_.newPropertyName(property->asPropertyName(),
                                                 tokenizer_->pos(nameStart)));
   BINJS_TRY_DECL(result, handler_.newPropertyAccess(object, name));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceSuper(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   return raiseError(
       "FIXME: Not implemented yet in this preview release (Super)");
 }
 
 /*
  interface SwitchCase : Node {
     Expression test;
     FrozenArray<Statement> consequent;
  }
 */
 template <typename Tok>
 JS::Result<CaseClause*> BinASTParser<Tok>::parseSwitchCase(
-    const Context& context) {
+    const ListContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::SwitchCase) {
     return raiseInvalidKind("SwitchCase", kind);
   }
@@ -4367,45 +4362,46 @@ JS::Result<CaseClause*> BinASTParser<Tok
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<CaseClause*> BinASTParser<Tok>::parseInterfaceSwitchCase(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const ListContext& context) {
   MOZ_ASSERT(kind == BinASTKind::SwitchCase);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Test,
                                           BinASTField::Consequent};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(test, parseExpression(Context(FieldContext(
-                               BinASTInterfaceAndField::SwitchCase__Test))));
+  BINJS_MOZ_TRY_DECL(
+      test,
+      parseExpression(FieldContext(BinASTInterfaceAndField::SwitchCase__Test)));
 
   BINJS_MOZ_TRY_DECL(consequent,
-                     parseListOfStatement(Context(FieldContext(
-                         BinASTInterfaceAndField::SwitchCase__Consequent))));
+                     parseListOfStatement(FieldContext(
+                         BinASTInterfaceAndField::SwitchCase__Consequent)));
 
   BINJS_TRY_DECL(result, handler_.newCaseOrDefault(start, test, consequent));
   return result;
 }
 
 /*
  interface SwitchDefault : Node {
     FrozenArray<Statement> consequent;
  }
 */
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseSwitchDefault(
-    const Context& context) {
+    const FieldContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::SwitchDefault) {
     return raiseInvalidKind("SwitchDefault", kind);
   }
@@ -4415,28 +4411,28 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceSwitchDefault(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const FieldContext& context) {
   MOZ_ASSERT(kind == BinASTKind::SwitchDefault);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Consequent};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   BINJS_MOZ_TRY_DECL(consequent,
-                     parseListOfStatement(Context(FieldContext(
-                         BinASTInterfaceAndField::SwitchDefault__Consequent))));
+                     parseListOfStatement(FieldContext(
+                         BinASTInterfaceAndField::SwitchDefault__Consequent)));
 
   BINJS_TRY_DECL(result, handler_.newCaseOrDefault(start, nullptr, consequent));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceSwitchStatement(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
@@ -4447,22 +4443,22 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Discriminant,
                                           BinASTField::Cases};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   BINJS_MOZ_TRY_DECL(
       discriminant,
-      parseExpression(Context(FieldContext(
-          BinASTInterfaceAndField::SwitchStatement__Discriminant))));
+      parseExpression(FieldContext(
+          BinASTInterfaceAndField::SwitchStatement__Discriminant)));
   ParseContext::Statement stmt(pc_, StatementKind::Switch);
   BINJS_MOZ_TRY_DECL(cases,
-                     parseListOfSwitchCase(Context(FieldContext(
-                         BinASTInterfaceAndField::SwitchStatement__Cases))));
+                     parseListOfSwitchCase(FieldContext(
+                         BinASTInterfaceAndField::SwitchStatement__Cases)));
 
   BINJS_TRY_DECL(scope, handler_.newLexicalScope(nullptr, cases));
   BINJS_TRY_DECL(result, handler_.newSwitchStatement(start, discriminant, scope,
                                                      /* hasDefault = */ false));
   return result;
 }
 
 template <typename Tok>
@@ -4477,33 +4473,33 @@ BinASTParser<Tok>::parseInterfaceSwitchS
   const BinASTField expected_fields[4] = {
       BinASTField::Discriminant, BinASTField::PreDefaultCases,
       BinASTField::DefaultCase, BinASTField::PostDefaultCases};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   BINJS_MOZ_TRY_DECL(
       discriminant,
-      parseExpression(Context(FieldContext(
-          BinASTInterfaceAndField::SwitchStatementWithDefault__Discriminant))));
+      parseExpression(FieldContext(
+          BinASTInterfaceAndField::SwitchStatementWithDefault__Discriminant)));
   ParseContext::Statement stmt(pc_, StatementKind::Switch);
   BINJS_MOZ_TRY_DECL(preDefaultCases,
-                     parseListOfSwitchCase(Context(FieldContext(
+                     parseListOfSwitchCase(FieldContext(
                          BinASTInterfaceAndField::
-                             SwitchStatementWithDefault__PreDefaultCases))));
+                             SwitchStatementWithDefault__PreDefaultCases)));
 
   BINJS_MOZ_TRY_DECL(
       defaultCase,
-      parseSwitchDefault(Context(FieldContext(
-          BinASTInterfaceAndField::SwitchStatementWithDefault__DefaultCase))));
+      parseSwitchDefault(FieldContext(
+          BinASTInterfaceAndField::SwitchStatementWithDefault__DefaultCase)));
 
   BINJS_MOZ_TRY_DECL(postDefaultCases,
-                     parseListOfSwitchCase(Context(FieldContext(
+                     parseListOfSwitchCase(FieldContext(
                          BinASTInterfaceAndField::
-                             SwitchStatementWithDefault__PostDefaultCases))));
+                             SwitchStatementWithDefault__PostDefaultCases)));
 
   // Concatenate `preDefaultCase`, `defaultCase`, `postDefaultCase`
   auto cases = preDefaultCases;
   handler_.addList(cases, defaultCase);
   ParseNode* iter = postDefaultCases->head();
   while (iter) {
     ParseNode* next = iter->pn_next;
     handler_.addList(cases, iter);
@@ -4556,19 +4552,19 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   MOZ_ASSERT(kind == BinASTKind::ThrowStatement);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[1] = {BinASTField::Expression};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(
-      expression, parseExpression(Context(FieldContext(
-                      BinASTInterfaceAndField::ThrowStatement__Expression))));
+  BINJS_MOZ_TRY_DECL(expression,
+                     parseExpression(FieldContext(
+                         BinASTInterfaceAndField::ThrowStatement__Expression)));
 
   BINJS_TRY_DECL(
       result, handler_.newThrowStatement(expression, tokenizer_->pos(start)));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceTryCatchStatement(
@@ -4589,18 +4585,18 @@ JS::Result<ParseNode*> BinASTParser<Tok>
     ParseContext::Scope scope(cx_, pc_, usedNames_);
     BINJS_TRY(scope.init(pc_));
     MOZ_TRY_VAR(body, parseBlock(Context(FieldContext(
                           BinASTInterfaceAndField::TryCatchStatement__Body))));
   }
 
   BINJS_MOZ_TRY_DECL(
       catchClause,
-      parseCatchClause(Context(FieldContext(
-          BinASTInterfaceAndField::TryCatchStatement__CatchClause))));
+      parseCatchClause(FieldContext(
+          BinASTInterfaceAndField::TryCatchStatement__CatchClause)));
 
   BINJS_TRY_DECL(result,
                  handler_.newTryStatement(start, body, catchClause,
                                           /* finallyBlock = */ nullptr));
   return result;
 }
 
 template <typename Tok>
@@ -4623,18 +4619,18 @@ JS::Result<ParseNode*> BinASTParser<Tok>
     BINJS_TRY(scope.init(pc_));
     MOZ_TRY_VAR(body,
                 parseBlock(Context(FieldContext(
                     BinASTInterfaceAndField::TryFinallyStatement__Body))));
   }
 
   BINJS_MOZ_TRY_DECL(
       catchClause,
-      parseOptionalCatchClause(Context(FieldContext(
-          BinASTInterfaceAndField::TryFinallyStatement__CatchClause))));
+      parseOptionalCatchClause(FieldContext(
+          BinASTInterfaceAndField::TryFinallyStatement__CatchClause)));
 
   ParseNode* finalizer;
   {
     ParseContext::Statement stmt(pc_, StatementKind::Finally);
     ParseContext::Scope scope(cx_, pc_, usedNames_);
     BINJS_TRY(scope.init(pc_));
     MOZ_TRY_VAR(finalizer,
                 parseBlock(Context(FieldContext(
@@ -4655,22 +4651,22 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Operator,
                                           BinASTField::Operand};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   BINJS_MOZ_TRY_DECL(operator_,
-                     parseUnaryOperator(Context(FieldContext(
-                         BinASTInterfaceAndField::UnaryExpression__Operator))));
+                     parseUnaryOperator(FieldContext(
+                         BinASTInterfaceAndField::UnaryExpression__Operator)));
 
   BINJS_MOZ_TRY_DECL(operand,
-                     parseExpression(Context(FieldContext(
-                         BinASTInterfaceAndField::UnaryExpression__Operand))));
+                     parseExpression(FieldContext(
+                         BinASTInterfaceAndField::UnaryExpression__Operand)));
 
   ParseNodeKind pnk;
   switch (operator_) {
     case UnaryOperator::Minus:
       pnk = ParseNodeKind::NegExpr;
       break;
     case UnaryOperator::Plus:
       pnk = ParseNodeKind::PosExpr;
@@ -4723,27 +4719,27 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[3] = {
       BinASTField::IsPrefix, BinASTField::Operator, BinASTField::Operand};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
-  BINJS_MOZ_TRY_DECL(
-      isPrefix, tokenizer_->readBool(Context(FieldContext(
-                    BinASTInterfaceAndField::UpdateExpression__IsPrefix))));
-
-  BINJS_MOZ_TRY_DECL(
-      operator_, parseUpdateOperator(Context(FieldContext(
-                     BinASTInterfaceAndField::UpdateExpression__Operator))));
+  BINJS_MOZ_TRY_DECL(isPrefix,
+                     tokenizer_->readBool(FieldContext(
+                         BinASTInterfaceAndField::UpdateExpression__IsPrefix)));
+
+  BINJS_MOZ_TRY_DECL(operator_,
+                     parseUpdateOperator(FieldContext(
+                         BinASTInterfaceAndField::UpdateExpression__Operator)));
 
   BINJS_MOZ_TRY_DECL(operand,
-                     parseSimpleAssignmentTarget(Context(FieldContext(
-                         BinASTInterfaceAndField::UpdateExpression__Operand))));
+                     parseSimpleAssignmentTarget(FieldContext(
+                         BinASTInterfaceAndField::UpdateExpression__Operand)));
 
   ParseNodeKind pnk;
   switch (operator_) {
     case UpdateOperator::Incr:
       pnk = isPrefix ? ParseNodeKind::PreIncrementExpr
                      : ParseNodeKind::PostIncrementExpr;
       break;
     case UpdateOperator::Decr:
@@ -4765,36 +4761,36 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Kind,
                                           BinASTField::Declarators};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   AutoVariableDeclarationKind kindGuard(this);
 
   BINJS_MOZ_TRY_DECL(kind_,
-                     parseVariableDeclarationKind(Context(FieldContext(
-                         BinASTInterfaceAndField::VariableDeclaration__Kind))));
+                     parseVariableDeclarationKind(FieldContext(
+                         BinASTInterfaceAndField::VariableDeclaration__Kind)));
   // Restored by `kindGuard`.
   variableDeclarationKind_ = kind_;
   ParseNodeKind declarationListKind;
   switch (kind_) {
     case VariableDeclarationKind::Var:
       declarationListKind = ParseNodeKind::VarStmt;
       break;
     case VariableDeclarationKind::Let:
       return raiseError("Let is not supported in this preview release");
     case VariableDeclarationKind::Const:
       return raiseError("Const is not supported in this preview release");
   }
   BINJS_MOZ_TRY_DECL(
       declarators,
       parseListOfVariableDeclarator(
           declarationListKind,
-          Context(FieldContext(
-              BinASTInterfaceAndField::VariableDeclaration__Declarators))));
+          FieldContext(
+              BinASTInterfaceAndField::VariableDeclaration__Declarators)));
 
   // By specification, the list may not be empty.
   if (declarators->empty()) {
     return raiseEmpty("VariableDeclaration");
   }
 
   auto result = declarators;
   return result;
@@ -4803,17 +4799,17 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 /*
  interface VariableDeclarator : Node {
     Binding binding;
     Expression? init;
  }
 */
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseVariableDeclarator(
-    const Context& context) {
+    const ListContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   if (kind != BinASTKind::VariableDeclarator) {
     return raiseInvalidKind("VariableDeclarator", kind);
   }
@@ -4823,33 +4819,33 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceVariableDeclarator(
     const size_t start, const BinASTKind kind, const BinASTFields& fields,
-    const Context& context) {
+    const ListContext& context) {
   MOZ_ASSERT(kind == BinASTKind::VariableDeclarator);
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Binding,
                                           BinASTField::Init};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   BINJS_MOZ_TRY_DECL(
-      binding, parseBinding(Context(FieldContext(
-                   BinASTInterfaceAndField::VariableDeclarator__Binding))));
+      binding, parseBinding(FieldContext(
+                   BinASTInterfaceAndField::VariableDeclarator__Binding)));
 
   BINJS_MOZ_TRY_DECL(init,
-                     parseOptionalExpression(Context(FieldContext(
-                         BinASTInterfaceAndField::VariableDeclarator__Init))));
+                     parseOptionalExpression(FieldContext(
+                         BinASTInterfaceAndField::VariableDeclarator__Init)));
 
   ParseNode* result;
   if (binding->isKind(ParseNodeKind::Name)) {
     // `var foo [= bar]``
     NameNode* bindingNameNode = &binding->template as<NameNode>();
     MOZ_TRY(checkBinding(bindingNameNode->atom()->asPropertyName()));
     if (init) {
       BINJS_TRY_VAR(
@@ -4882,19 +4878,18 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   BINJS_TRY(CheckRecursionLimit(cx_));
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Test, BinASTField::Body};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
   ParseContext::Statement stmt(pc_, StatementKind::WhileLoop);
 
-  BINJS_MOZ_TRY_DECL(
-      test, parseExpression(Context(
-                FieldContext(BinASTInterfaceAndField::WhileStatement__Test))));
+  BINJS_MOZ_TRY_DECL(test, parseExpression(FieldContext(
+                               BinASTInterfaceAndField::WhileStatement__Test)));
 
   BINJS_MOZ_TRY_DECL(
       body, parseStatement(Context(
                 FieldContext(BinASTInterfaceAndField::WhileStatement__Body))));
 
   BINJS_TRY_DECL(result, handler_.newWhileStatement(start, test, body));
   return result;
 }
@@ -4908,18 +4903,18 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 
 #if defined(DEBUG)
   const BinASTField expected_fields[2] = {BinASTField::Object,
                                           BinASTField::Body};
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   BINJS_MOZ_TRY_DECL(object,
-                     parseExpression(Context(FieldContext(
-                         BinASTInterfaceAndField::WithStatement__Object))));
+                     parseExpression(FieldContext(
+                         BinASTInterfaceAndField::WithStatement__Object)));
 
   ParseContext::Statement stmt(pc_, StatementKind::With);
   BINJS_MOZ_TRY_DECL(body, parseStatement(Context(FieldContext(
                                BinASTInterfaceAndField::WithStatement__Body))));
 
   pc_->sc()->setBindingsAccessedDynamically();
   BINJS_TRY_DECL(result, handler_.newWithStatement(start, object, body));
   return result;
@@ -4947,17 +4942,17 @@ JS::Result<ParseNode*> BinASTParser<Tok>
 enum AssertedDeclaredKind {
     "var",
     "non-const lexical",
     "const lexical"
 };
 */
 template <typename Tok>
 JS::Result<typename BinASTParser<Tok>::AssertedDeclaredKind>
-BinASTParser<Tok>::parseAssertedDeclaredKind(const Context& context) {
+BinASTParser<Tok>::parseAssertedDeclaredKind(const FieldContext& context) {
   BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant(context));
 
   switch (variant) {
     case BinASTVariant::AssertedDeclaredKindOrVariableDeclarationKindVar:
       return AssertedDeclaredKind::Var;
     case BinASTVariant::AssertedDeclaredKindNonConstLexical:
       return AssertedDeclaredKind::NonConstLexical;
     case BinASTVariant::AssertedDeclaredKindConstLexical:
@@ -4993,17 +4988,17 @@ enum BinaryOperator {
     "*",
     "/",
     "%",
     "**"
 };
 */
 template <typename Tok>
 JS::Result<typename BinASTParser<Tok>::BinaryOperator>
-BinASTParser<Tok>::parseBinaryOperator(const Context& context) {
+BinASTParser<Tok>::parseBinaryOperator(const FieldContext& context) {
   BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant(context));
 
   switch (variant) {
     case BinASTVariant::BinaryOperatorComma:
       return BinaryOperator::Comma;
     case BinASTVariant::BinaryOperatorLogicalOr:
       return BinaryOperator::LogicalOr;
     case BinASTVariant::BinaryOperatorLogicalAnd:
@@ -5070,17 +5065,18 @@ enum CompoundAssignmentOperator {
     ">>>=",
     "|=",
     "^=",
     "&="
 };
 */
 template <typename Tok>
 JS::Result<typename BinASTParser<Tok>::CompoundAssignmentOperator>
-BinASTParser<Tok>::parseCompoundAssignmentOperator(const Context& context) {
+BinASTParser<Tok>::parseCompoundAssignmentOperator(
+    const FieldContext& context) {
   BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant(context));
 
   switch (variant) {
     case BinASTVariant::CompoundAssignmentOperatorPlusAssign:
       return CompoundAssignmentOperator::PlusAssign;
     case BinASTVariant::CompoundAssignmentOperatorMinusAssign:
       return CompoundAssignmentOperator::MinusAssign;
     case BinASTVariant::CompoundAssignmentOperatorMulAssign:
@@ -5116,17 +5112,17 @@ enum UnaryOperator {
     "~",
     "typeof",
     "void",
     "delete"
 };
 */
 template <typename Tok>
 JS::Result<typename BinASTParser<Tok>::UnaryOperator>
-BinASTParser<Tok>::parseUnaryOperator(const Context& context) {
+BinASTParser<Tok>::parseUnaryOperator(const FieldContext& context) {
   BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant(context));
 
   switch (variant) {
     case BinASTVariant::BinaryOperatorOrUnaryOperatorPlus:
       return UnaryOperator::Plus;
     case BinASTVariant::BinaryOperatorOrUnaryOperatorMinus:
       return UnaryOperator::Minus;
     case BinASTVariant::UnaryOperatorNot:
@@ -5147,17 +5143,17 @@ BinASTParser<Tok>::parseUnaryOperator(co
 /*
 enum UpdateOperator {
     "++",
     "--"
 };
 */
 template <typename Tok>
 JS::Result<typename BinASTParser<Tok>::UpdateOperator>
-BinASTParser<Tok>::parseUpdateOperator(const Context& context) {
+BinASTParser<Tok>::parseUpdateOperator(const FieldContext& context) {
   BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant(context));
 
   switch (variant) {
     case BinASTVariant::UpdateOperatorIncr:
       return UpdateOperator::Incr;
     case BinASTVariant::UpdateOperatorDecr:
       return UpdateOperator::Decr;
     default:
@@ -5169,17 +5165,17 @@ BinASTParser<Tok>::parseUpdateOperator(c
 enum VariableDeclarationKind {
     "var",
     "let",
     "const"
 };
 */
 template <typename Tok>
 JS::Result<typename BinASTParser<Tok>::VariableDeclarationKind>
-BinASTParser<Tok>::parseVariableDeclarationKind(const Context& context) {
+BinASTParser<Tok>::parseVariableDeclarationKind(const FieldContext& context) {
   BINJS_MOZ_TRY_DECL(variant, tokenizer_->readVariant(context));
 
   switch (variant) {
     case BinASTVariant::AssertedDeclaredKindOrVariableDeclarationKindVar:
       return VariableDeclarationKind::Var;
     case BinASTVariant::VariableDeclarationKindLet:
       return VariableDeclarationKind::Let;
     case BinASTVariant::VariableDeclarationKindConst:
@@ -5188,90 +5184,88 @@ BinASTParser<Tok>::parseVariableDeclarat
       return raiseInvalidVariant("VariableDeclarationKind", variant);
   }
 }
 
 // ----- Lists (autogenerated, by lexicographical order)
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseArguments(
-    const Context& context) {
+    const FieldContext& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  const Context childContext(Context(
-      ListContext(context.as<FieldContext>().position, BinASTList::Arguments)));
+  const auto childContext =
+      ListContext(context.position, BinASTList::Arguments);
   MOZ_TRY(tokenizer_->enterList(length, childContext, guard));
   BINJS_TRY_DECL(result, handler_.newList(ParseNodeKind::Arguments,
                                           tokenizer_->pos(start)));
 
   for (uint32_t i = 0; i < length; ++i) {
     BINJS_MOZ_TRY_DECL(item, parseExpressionOrSpreadElement(childContext));
     handler_.addList(/* list = */ result, /* kid = */ item);
   }
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ListNode*> BinASTParser<Tok>::parseFunctionBody(
-    const Context& context) {
+    const FieldContext& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  const Context childContext(Context(ListContext(
-      context.as<FieldContext>().position, BinASTList::ListOfStatement)));
+  const auto childContext =
+      ListContext(context.position, BinASTList::ListOfStatement);
   MOZ_TRY(tokenizer_->enterList(length, childContext, guard));
   BINJS_TRY_DECL(result, handler_.newStatementList(tokenizer_->pos(start)));
 
   for (uint32_t i = 0; i < length; ++i) {
-    BINJS_MOZ_TRY_DECL(item, parseStatement(childContext));
+    BINJS_MOZ_TRY_DECL(item, parseStatement(Context(childContext)));
     handler_.addStatementToList(result, item);
   }
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseListOfAssertedBoundName(
-    AssertedScopeKind scopeKind, const Context& context) {
+    AssertedScopeKind scopeKind, const FieldContext& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  const Context childContext(
-      Context(ListContext(context.as<FieldContext>().position,
-                          BinASTList::ListOfAssertedBoundName)));
+  const auto childContext =
+      ListContext(context.position, BinASTList::ListOfAssertedBoundName);
   MOZ_TRY(tokenizer_->enterList(length, childContext, guard));
   (void)start;
   auto result = Ok();
 
   for (uint32_t i = 0; i < length; ++i) {
     MOZ_TRY(parseAssertedBoundName(scopeKind, childContext));
     // Nothing to do here.
   }
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok> BinASTParser<Tok>::parseListOfAssertedDeclaredName(
-    AssertedScopeKind scopeKind, const Context& context) {
+    AssertedScopeKind scopeKind, const FieldContext& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  const Context childContext(
-      Context(ListContext(context.as<FieldContext>().position,
-                          BinASTList::ListOfAssertedDeclaredName)));
+  const auto childContext =
+      ListContext(context.position, BinASTList::ListOfAssertedDeclaredName);
   MOZ_TRY(tokenizer_->enterList(length, childContext, guard));
   (void)start;
   auto result = Ok();
 
   for (uint32_t i = 0; i < length; ++i) {
     MOZ_TRY(parseAssertedDeclaredName(scopeKind, childContext));
     // Nothing to do here.
   }
@@ -5279,24 +5273,24 @@ JS::Result<Ok> BinASTParser<Tok>::parseL
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<Ok>
 BinASTParser<Tok>::parseListOfAssertedMaybePositionalParameterName(
     AssertedScopeKind scopeKind,
-    MutableHandle<GCVector<JSAtom*>> positionalParams, const Context& context) {
+    MutableHandle<GCVector<JSAtom*>> positionalParams,
+    const FieldContext& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  const Context childContext(Context(
-      ListContext(context.as<FieldContext>().position,
-                  BinASTList::ListOfAssertedMaybePositionalParameterName)));
+  const auto childContext = ListContext(
+      context.position, BinASTList::ListOfAssertedMaybePositionalParameterName);
   MOZ_TRY(tokenizer_->enterList(length, childContext, guard));
   (void)start;
   auto result = Ok();
   // This list contains also destructuring parameters, and the number of
   // list items can be greater than the actual parameters, or more than
   // ARGNO_LIMIT even if the number of parameters fits into ARGNO_LIMIT.
   // Also, the number of parameters can be greater than this list's length
   // if one of destructuring parameter is empty.
@@ -5311,68 +5305,67 @@ BinASTParser<Tok>::parseListOfAssertedMa
   }
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ListNode*> BinASTParser<Tok>::parseListOfDirective(
-    const Context& context) {
+    const FieldContext& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  const Context childContext(Context(ListContext(
-      context.as<FieldContext>().position, BinASTList::ListOfDirective)));
+  const auto childContext =
+      ListContext(context.position, BinASTList::ListOfDirective);
   MOZ_TRY(tokenizer_->enterList(length, childContext, guard));
   BINJS_TRY_DECL(result, handler_.newStatementList(tokenizer_->pos(start)));
 
   for (uint32_t i = 0; i < length; ++i) {
     BINJS_MOZ_TRY_DECL(item, parseDirective(childContext));
     handler_.addStatementToList(result, item);
   }
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ListNode*> BinASTParser<Tok>::parseListOfObjectProperty(
-    const Context& context) {
+    const FieldContext& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  const Context childContext(Context(ListContext(
-      context.as<FieldContext>().position, BinASTList::ListOfObjectProperty)));
+  const auto childContext =
+      ListContext(context.position, BinASTList::ListOfObjectProperty);
   MOZ_TRY(tokenizer_->enterList(length, childContext, guard));
   BINJS_TRY_DECL(result, handler_.newObjectLiteral(start));
 
   for (uint32_t i = 0; i < length; ++i) {
     BINJS_MOZ_TRY_DECL(item, parseObjectProperty(childContext));
     if (!item->isConstant()) result->setHasNonConstInitializer();
     result->appendWithoutOrderAssumption(item);
   }
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ListNode*>
 BinASTParser<Tok>::parseListOfOptionalExpressionOrSpreadElement(
-    const Context& context) {
+    const FieldContext& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  const Context childContext(Context(
-      ListContext(context.as<FieldContext>().position,
-                  BinASTList::ListOfOptionalExpressionOrSpreadElement)));
+  const auto childContext = ListContext(
+      context.position, BinASTList::ListOfOptionalExpressionOrSpreadElement);
   MOZ_TRY(tokenizer_->enterList(length, childContext, guard));
   BINJS_TRY_DECL(result, handler_.newArrayLiteral(start));
 
   for (uint32_t i = 0; i < length; ++i) {
     BINJS_MOZ_TRY_DECL(item,
                        parseOptionalExpressionOrSpreadElement(childContext));
     if (item) {
       handler_.addArrayElement(result, item);  // Infallible.
@@ -5382,104 +5375,103 @@ BinASTParser<Tok>::parseListOfOptionalEx
   }
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ListNode*> BinASTParser<Tok>::parseListOfParameter(
-    const Context& context) {
+    const FieldContext& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  const Context childContext(Context(ListContext(
-      context.as<FieldContext>().position, BinASTList::ListOfParameter)));
+  const auto childContext =
+      ListContext(context.position, BinASTList::ListOfParameter);
   MOZ_TRY(tokenizer_->enterList(length, childContext, guard));
   BINJS_TRY_DECL(result, handler_.newParamsBody(tokenizer_->pos(start)));
 
   for (uint32_t i = 0; i < length; ++i) {
-    BINJS_MOZ_TRY_DECL(item, parseParameter(childContext));
+    BINJS_MOZ_TRY_DECL(item, parseParameter(Context(childContext)));
     handler_.addList(/* list = */ result, /* kid = */ item);
   }
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ListNode*> BinASTParser<Tok>::parseListOfStatement(
-    const Context& context) {
+    const FieldContext& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  const Context childContext(Context(ListContext(
-      context.as<FieldContext>().position, BinASTList::ListOfStatement)));
+  const auto childContext =
+      ListContext(context.position, BinASTList::ListOfStatement);
   MOZ_TRY(tokenizer_->enterList(length, childContext, guard));
   BINJS_TRY_DECL(result, handler_.newStatementList(tokenizer_->pos(start)));
 
   for (uint32_t i = 0; i < length; ++i) {
-    BINJS_MOZ_TRY_DECL(item, parseStatement(childContext));
+    BINJS_MOZ_TRY_DECL(item, parseStatement(Context(childContext)));
     handler_.addStatementToList(result, item);
   }
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ListNode*> BinASTParser<Tok>::parseListOfSwitchCase(
-    const Context& context) {
+    const FieldContext& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  const Context childContext(Context(ListContext(
-      context.as<FieldContext>().position, BinASTList::ListOfSwitchCase)));
+  const auto childContext =
+      ListContext(context.position, BinASTList::ListOfSwitchCase);
   MOZ_TRY(tokenizer_->enterList(length, childContext, guard));
   BINJS_TRY_DECL(result, handler_.newStatementList(tokenizer_->pos(start)));
 
   for (uint32_t i = 0; i < length; ++i) {
     BINJS_MOZ_TRY_DECL(item, parseSwitchCase(childContext));
     handler_.addCaseStatementToList(result, item);
   }
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 template <typename Tok>
 JS::Result<ListNode*> BinASTParser<Tok>::parseListOfVariableDeclarator(
-    ParseNodeKind declarationListKind, const Context& context) {
+    ParseNodeKind declarationListKind, const FieldContext& context) {
   uint32_t length;
   AutoList guard(*tokenizer_);
 
   const auto start = tokenizer_->offset();
-  const Context childContext(
-      Context(ListContext(context.as<FieldContext>().position,
-                          BinASTList::ListOfVariableDeclarator)));
+  const auto childContext =
+      ListContext(context.position, BinASTList::ListOfVariableDeclarator);
   MOZ_TRY(tokenizer_->enterList(length, childContext, guard));
   BINJS_TRY_DECL(result, handler_.newDeclarationList(declarationListKind,
                                                      tokenizer_->pos(start)));
 
   for (uint32_t i = 0; i < length; ++i) {
     BINJS_MOZ_TRY_DECL(item, parseVariableDeclarator(childContext));
     result->appendWithoutOrderAssumption(item);
   }
 
   MOZ_TRY(guard.done());
   return result;
 }
 
 // ----- Default values (by lexicographical order)
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseOptionalBinding(
-    const Context& context) {
+    const FieldContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   ParseNode* result;
   if (kind == BinASTKind::_Null) {
     result = nullptr;
@@ -5489,40 +5481,40 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   }
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseOptionalBindingIdentifier(
-    const Context& context) {
+    const FieldContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   ParseNode* result;
   if (kind == BinASTKind::_Null) {
     result = nullptr;
   } else if (kind == BinASTKind::BindingIdentifier) {
     const auto start = tokenizer_->offset();
-    MOZ_TRY_VAR(result,
-                parseInterfaceBindingIdentifier(start, kind, fields, context));
+    MOZ_TRY_VAR(result, parseInterfaceBindingIdentifier(start, kind, fields,
+                                                        Context(context)));
   } else {
     return raiseInvalidKind("BindingIdentifier", kind);
   }
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<LexicalScopeNode*> BinASTParser<Tok>::parseOptionalCatchClause(
-    const Context& context) {
+    const FieldContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   LexicalScopeNode* result;
   if (kind == BinASTKind::_Null) {
     result = nullptr;
@@ -5535,17 +5527,17 @@ JS::Result<LexicalScopeNode*> BinASTPars
   }
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseOptionalExpression(
-    const Context& context) {
+    const FieldContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   ParseNode* result;
   if (kind == BinASTKind::_Null) {
     result = nullptr;
@@ -5556,17 +5548,17 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseOptionalExpressionOrSpreadElement(
-    const Context& context) {
+    const ListContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   ParseNode* result;
   if (kind == BinASTKind::_Null) {
     result = nullptr;
@@ -5578,17 +5570,17 @@ BinASTParser<Tok>::parseOptionalExpressi
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*>
 BinASTParser<Tok>::parseOptionalExpressionOrVariableDeclaration(
-    const Context& context) {
+    const FieldContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   ParseNode* result;
   if (kind == BinASTKind::_Null) {
     result = nullptr;
@@ -5599,28 +5591,29 @@ BinASTParser<Tok>::parseOptionalExpressi
   }
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseOptionalStatement(
-    const Context& context) {
+    const FieldContext& context) {
   BinASTKind kind;
   BinASTFields fields(cx_);
   AutoTaggedTuple guard(*tokenizer_);
 
   MOZ_TRY(tokenizer_->enterTaggedTuple(kind, fields, context, guard));
   ParseNode* result;
   if (kind == BinASTKind::_Null) {
     result = nullptr;
   } else {
     const auto start = tokenizer_->offset();
-    MOZ_TRY_VAR(result, parseSumStatement(start, kind, fields, context));
+    MOZ_TRY_VAR(result,
+                parseSumStatement(start, kind, fields, Context(context)));
   }
   MOZ_TRY(guard.done());
 
   return result;
 }
 
 // Force class instantiation.
 // This ensures that the symbols are built, without having to export all our
--- a/js/src/frontend/BinASTParser.h
+++ b/js/src/frontend/BinASTParser.h
@@ -126,169 +126,171 @@ class BinASTParser : public BinASTParser
   using Base::forceStrictIfNecessary;
 
  public:
   // ----- Sums of interfaces (by lexicographical order)
   // `ParseNode*` may never be nullptr
   JS::Result<Ok> parseAssertedMaybePositionalParameterName(
       AssertedScopeKind scopeKind,
       MutableHandle<GCVector<JSAtom*>> positionalParams,
-      const Context& context);
-  JS::Result<ParseNode*> parseAssignmentTarget(const Context& context);
+      const ListContext& context);
+  JS::Result<ParseNode*> parseAssignmentTarget(const FieldContext& context);
   JS::Result<ParseNode*> parseAssignmentTargetOrForInOfBinding(
-      const Context& context);
-  JS::Result<ParseNode*> parseBinding(const Context& context);
-  JS::Result<ParseNode*> parseExpression(const Context& context);
-  JS::Result<ParseNode*> parseExpressionOrSpreadElement(const Context& context);
-  JS::Result<ParseNode*> parseExpressionOrSuper(const Context& context);
-  JS::Result<ParseNode*> parseObjectProperty(const Context& context);
+      const FieldContext& context);
+  JS::Result<ParseNode*> parseBinding(const FieldContext& context);
+  JS::Result<ParseNode*> parseExpression(const FieldContext& context);
+  JS::Result<ParseNode*> parseExpressionOrSpreadElement(
+      const ListContext& context);
+  JS::Result<ParseNode*> parseExpressionOrSuper(const FieldContext& context);
+  JS::Result<ParseNode*> parseObjectProperty(const ListContext& context);
   JS::Result<ParseNode*> parseParameter(const Context& context);
-  JS::Result<ParseNode*> parseProgram(const Context& context);
-  JS::Result<ParseNode*> parsePropertyName(const Context& context);
-  JS::Result<ParseNode*> parseSimpleAssignmentTarget(const Context& context);
+  JS::Result<ParseNode*> parseProgram(const RootContext& context);
+  JS::Result<ParseNode*> parsePropertyName(const FieldContext& context);
+  JS::Result<ParseNode*> parseSimpleAssignmentTarget(
+      const FieldContext& context);
   JS::Result<ParseNode*> parseStatement(const Context& context);
   JS::Result<Ok> parseSumAssertedMaybePositionalParameterName(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       AssertedScopeKind scopeKind,
       MutableHandle<GCVector<JSAtom*>> positionalParams,
-      const Context& context);
+      const ListContext& context);
   JS::Result<ParseNode*> parseSumAssignmentTarget(const size_t start,
                                                   const BinASTKind kind,
                                                   const BinASTFields& fields,
-                                                  const Context& context);
+                                                  const FieldContext& context);
   JS::Result<ParseNode*> parseSumAssignmentTargetOrForInOfBinding(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      const Context& context);
+      const FieldContext& context);
   JS::Result<ParseNode*> parseSumBinding(const size_t start,
                                          const BinASTKind kind,
                                          const BinASTFields& fields,
-                                         const Context& context);
+                                         const FieldContext& context);
   JS::Result<ParseNode*> parseSumExpression(const size_t start,
                                             const BinASTKind kind,
                                             const BinASTFields& fields,
-                                            const Context& context);
+                                            const FieldContext& context);
   JS::Result<ParseNode*> parseSumExpressionOrSpreadElement(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      const Context& context);
+      const ListContext& context);
   JS::Result<ParseNode*> parseSumExpressionOrSuper(const size_t start,
                                                    const BinASTKind kind,
                                                    const BinASTFields& fields,
-                                                   const Context& context);
+                                                   const FieldContext& context);
   JS::Result<ParseNode*> parseSumExpressionOrVariableDeclaration(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      const Context& context);
+      const FieldContext& context);
   JS::Result<ParseNode*> parseSumObjectProperty(const size_t start,
                                                 const BinASTKind kind,
                                                 const BinASTFields& fields,
-                                                const Context& context);
+                                                const ListContext& context);
   JS::Result<ParseNode*> parseSumParameter(const size_t start,
                                            const BinASTKind kind,
                                            const BinASTFields& fields,
                                            const Context& context);
   JS::Result<ParseNode*> parseSumProgram(const size_t start,
                                          const BinASTKind kind,
                                          const BinASTFields& fields,
-                                         const Context& context);
+                                         const RootContext& context);
   JS::Result<ParseNode*> parseSumPropertyName(const size_t start,
                                               const BinASTKind kind,
                                               const BinASTFields& fields,
-                                              const Context& context);
+                                              const FieldContext& context);
   JS::Result<ParseNode*> parseSumSimpleAssignmentTarget(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      const Context& context);
+      const FieldContext& context);
   JS::Result<ParseNode*> parseSumStatement(const size_t start,
                                            const BinASTKind kind,
                                            const BinASTFields& fields,
                                            const Context& context);
 
   // ----- Interfaces (by lexicographical order)
   // `ParseNode*` may never be nullptr
-  JS::Result<Ok> parseAssertedBlockScope(const Context& context);
+  JS::Result<Ok> parseAssertedBlockScope(const FieldContext& context);
   JS::Result<Ok> parseAssertedBoundName(AssertedScopeKind scopeKind,
-                                        const Context& context);
-  JS::Result<Ok> parseAssertedBoundNamesScope(const Context& context);
+                                        const ListContext& context);
+  JS::Result<Ok> parseAssertedBoundNamesScope(const FieldContext& context);
   JS::Result<Ok> parseAssertedDeclaredName(AssertedScopeKind scopeKind,
-                                           const Context& context);
+                                           const ListContext& context);
   JS::Result<Ok> parseAssertedParameterScope(
       MutableHandle<GCVector<JSAtom*>> positionalParams,
-      const Context& context);
-  JS::Result<Ok> parseAssertedScriptGlobalScope(const Context& context);
-  JS::Result<Ok> parseAssertedVarScope(const Context& context);
+      const FieldContext& context);
+  JS::Result<Ok> parseAssertedScriptGlobalScope(const FieldContext& context);
+  JS::Result<Ok> parseAssertedVarScope(const FieldContext& context);
   JS::Result<ParseNode*> parseBindingIdentifier(const Context& context);
   JS::Result<ParseNode*> parseBlock(const Context& context);
-  JS::Result<LexicalScopeNode*> parseCatchClause(const Context& context);
-  JS::Result<ParseNode*> parseDirective(const Context& context);
-  JS::Result<ListNode*> parseFormalParameters(const Context& context);
+  JS::Result<LexicalScopeNode*> parseCatchClause(const FieldContext& context);
+  JS::Result<ParseNode*> parseDirective(const ListContext& context);
+  JS::Result<ListNode*> parseFormalParameters(const FieldContext& context);
   JS::Result<Ok> parseFunctionExpressionContents(uint32_t funLength,
                                                  ListNode** paramsOut,
                                                  ListNode** bodyOut,
                                                  const Context& context);
   JS::Result<Ok> parseFunctionOrMethodContents(uint32_t funLength,
                                                ListNode** paramsOut,
                                                ListNode** bodyOut,
                                                const Context& context);
   JS::Result<Ok> parseGetterContents(uint32_t funLength, ListNode** paramsOut,
                                      ListNode** bodyOut,
-                                     const Context& context);
+                                     const FieldContext& context);
   JS::Result<ParseNode*> parseIdentifierExpression(const Context& context);
   JS::Result<Ok> parseSetterContents(uint32_t funLength, ListNode** paramsOut,
                                      ListNode** bodyOut,
-                                     const Context& context);
-  JS::Result<CaseClause*> parseSwitchCase(const Context& context);
-  JS::Result<ParseNode*> parseSwitchDefault(const Context& context);
-  JS::Result<ParseNode*> parseVariableDeclarator(const Context& context);
+                                     const FieldContext& context);
+  JS::Result<CaseClause*> parseSwitchCase(const ListContext& context);
+  JS::Result<ParseNode*> parseSwitchDefault(const FieldContext& context);
+  JS::Result<ParseNode*> parseVariableDeclarator(const ListContext& context);
   JS::Result<ParseNode*> parseInterfaceArrayAssignmentTarget(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      const Context& context);
+      const FieldContext& context);
   JS::Result<ParseNode*> parseInterfaceArrayBinding(const size_t start,
                                                     const BinASTKind kind,
                                                     const BinASTFields& fields,
                                                     const Context& context);
   JS::Result<ParseNode*> parseInterfaceArrayExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<Ok> parseInterfaceAssertedBlockScope(const size_t start,
                                                   const BinASTKind kind,
                                                   const BinASTFields& fields,
-                                                  const Context& context);
+                                                  const FieldContext& context);
   JS::Result<Ok> parseInterfaceAssertedBoundName(const size_t start,
                                                  const BinASTKind kind,
                                                  const BinASTFields& fields,
                                                  AssertedScopeKind scopeKind,
-                                                 const Context& context);
+                                                 const ListContext& context);
   JS::Result<Ok> parseInterfaceAssertedBoundNamesScope(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      const Context& context);
+      const FieldContext& context);
   JS::Result<Ok> parseInterfaceAssertedDeclaredName(const size_t start,
                                                     const BinASTKind kind,
                                                     const BinASTFields& fields,
                                                     AssertedScopeKind scopeKind,
-                                                    const Context& context);
+                                                    const ListContext& context);
   JS::Result<Ok> parseInterfaceAssertedParameterScope(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       MutableHandle<GCVector<JSAtom*>> positionalParams,
-      const Context& context);
+      const FieldContext& context);
   JS::Result<Ok> parseInterfaceAssertedPositionalParameterName(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       AssertedScopeKind scopeKind,
       MutableHandle<GCVector<JSAtom*>> positionalParams,
-      const Context& context);
+      const ListContext& context);
   JS::Result<Ok> parseInterfaceAssertedScriptGlobalScope(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      const Context& context);
+      const FieldContext& context);
   JS::Result<Ok> parseInterfaceAssertedVarScope(const size_t start,
                                                 const BinASTKind kind,
                                                 const BinASTFields& fields,
-                                                const Context& context);
+                                                const FieldContext& context);
   JS::Result<ParseNode*> parseInterfaceAssignmentExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceAssignmentTargetIdentifier(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      const Context& context);
+      const FieldContext& context);
   JS::Result<ParseNode*> parseInterfaceAwaitExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceBinaryExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceBindingIdentifier(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
@@ -303,52 +305,52 @@ class BinASTParser : public BinASTParser
   JS::Result<ParseNode*> parseInterfaceBreakStatement(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceCallExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<LexicalScopeNode*> parseInterfaceCatchClause(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      const Context& context);
+      const FieldContext& context);
   JS::Result<ParseNode*> parseInterfaceClassDeclaration(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceClassExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceCompoundAssignmentExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceComputedMemberAssignmentTarget(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      const Context& context);
+      const FieldContext& context);
   JS::Result<ParseNode*> parseInterfaceComputedMemberExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceComputedPropertyName(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      const Context& context);
+      const FieldContext& context);
   JS::Result<ParseNode*> parseInterfaceConditionalExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceContinueStatement(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceDataProperty(const size_t start,
                                                     const BinASTKind kind,
                                                     const BinASTFields& fields,
-                                                    const Context& context);
+                                                    const ListContext& context);
   JS::Result<ParseNode*> parseInterfaceDebuggerStatement(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceDirective(const size_t start,
                                                  const BinASTKind kind,
                                                  const BinASTFields& fields,
-                                                 const Context& context);
+                                                 const ListContext& context);
   JS::Result<ParseNode*> parseInterfaceDoWhileStatement(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceEagerArrowExpressionWithExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceEagerArrowExpressionWithFunctionBody(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
@@ -357,59 +359,59 @@ class BinASTParser : public BinASTParser
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceEagerFunctionExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceEagerGetter(const size_t start,
                                                    const BinASTKind kind,
                                                    const BinASTFields& fields,
-                                                   const Context& context);
+                                                   const ListContext& context);
   JS::Result<ParseNode*> parseInterfaceEagerMethod(const size_t start,
                                                    const BinASTKind kind,
                                                    const BinASTFields& fields,
-                                                   const Context& context);
+                                                   const ListContext& context);
   JS::Result<ParseNode*> parseInterfaceEagerSetter(const size_t start,
                                                    const BinASTKind kind,
                                                    const BinASTFields& fields,
-                                                   const Context& context);
+                                                   const ListContext& context);
   JS::Result<ParseNode*> parseInterfaceEmptyStatement(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceExpressionStatement(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceForInOfBinding(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      const Context& context);
+      const FieldContext& context);
   JS::Result<ParseNode*> parseInterfaceForInStatement(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceForOfStatement(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceForStatement(const size_t start,
                                                     const BinASTKind kind,
                                                     const BinASTFields& fields,
                                                     const Context& context);
   JS::Result<ListNode*> parseInterfaceFormalParameters(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      const Context& context);
+      const FieldContext& context);
   JS::Result<Ok> parseInterfaceFunctionExpressionContents(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut,
       const Context& context);
   JS::Result<Ok> parseInterfaceFunctionOrMethodContents(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut,
       const Context& context);
   JS::Result<Ok> parseInterfaceGetterContents(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut,
-      const Context& context);
+      const FieldContext& context);
   JS::Result<ParseNode*> parseInterfaceIdentifierExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceIfStatement(const size_t start,
                                                    const BinASTKind kind,
                                                    const BinASTFields& fields,
                                                    const Context& context);
   JS::Result<ParseNode*> parseInterfaceLabelledStatement(
@@ -425,103 +427,101 @@ class BinASTParser : public BinASTParser
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceLazyFunctionExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceLazyGetter(const size_t start,
                                                   const BinASTKind kind,
                                                   const BinASTFields& fields,
-                                                  const Context& context);
+                                                  const ListContext& context);
   JS::Result<ParseNode*> parseInterfaceLazyMethod(const size_t start,
                                                   const BinASTKind kind,
                                                   const BinASTFields& fields,
-                                                  const Context& context);
+                                                  const ListContext& context);
   JS::Result<ParseNode*> parseInterfaceLazySetter(const size_t start,
                                                   const BinASTKind kind,
                                                   const BinASTFields& fields,
-                                                  const Context& context);
+                                                  const ListContext& context);
   JS::Result<ParseNode*> parseInterfaceLiteralBooleanExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceLiteralInfinityExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceLiteralNullExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceLiteralNumericExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceLiteralPropertyName(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      const Context& context);
+      const FieldContext& context);
   JS::Result<ParseNode*> parseInterfaceLiteralRegExpExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceLiteralStringExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceModule(const size_t start,
                                               const BinASTKind kind,
                                               const BinASTFields& fields,
-                                              const Context& context);
+                                              const RootContext& context);
   JS::Result<ParseNode*> parseInterfaceNewExpression(const size_t start,
                                                      const BinASTKind kind,
                                                      const BinASTFields& fields,
                                                      const Context& context);
   JS::Result<ParseNode*> parseInterfaceNewTargetExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceObjectAssignmentTarget(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      const Context& context);
+      const FieldContext& context);
   JS::Result<ParseNode*> parseInterfaceObjectBinding(const size_t start,
                                                      const BinASTKind kind,
                                                      const BinASTFields& fields,
                                                      const Context& context);
   JS::Result<ParseNode*> parseInterfaceObjectExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceReturnStatement(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceScript(const size_t start,
                                               const BinASTKind kind,
                                               const BinASTFields& fields,
-                                              const Context& context);
+                                              const RootContext& context);
   JS::Result<Ok> parseInterfaceSetterContents(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       uint32_t funLength, ListNode** paramsOut, ListNode** bodyOut,
-      const Context& context);
+      const FieldContext& context);
   JS::Result<ParseNode*> parseInterfaceShorthandProperty(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      const Context& context);
-  JS::Result<ParseNode*> parseInterfaceSpreadElement(const size_t start,
-                                                     const BinASTKind kind,
-                                                     const BinASTFields& fields,
-                                                     const Context& context);
+      const ListContext& context);
+  JS::Result<ParseNode*> parseInterfaceSpreadElement(
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const ListContext& context);
   JS::Result<ParseNode*> parseInterfaceStaticMemberAssignmentTarget(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      const Context& context);
+      const FieldContext& context);
   JS::Result<ParseNode*> parseInterfaceStaticMemberExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceSuper(const size_t start,
                                              const BinASTKind kind,
                                              const BinASTFields& fields,
-                                             const Context& context);
+                                             const FieldContext& context);
   JS::Result<CaseClause*> parseInterfaceSwitchCase(const size_t start,
                                                    const BinASTKind kind,
                                                    const BinASTFields& fields,
-                                                   const Context& context);
-  JS::Result<ParseNode*> parseInterfaceSwitchDefault(const size_t start,
-                                                     const BinASTKind kind,
-                                                     const BinASTFields& fields,
-                                                     const Context& context);
+                                                   const ListContext& context);
+  JS::Result<ParseNode*> parseInterfaceSwitchDefault(
+      const size_t start, const BinASTKind kind, const BinASTFields& fields,
+      const FieldContext& context);
   JS::Result<ParseNode*> parseInterfaceSwitchStatement(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceSwitchStatementWithDefault(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceTemplateExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
@@ -544,77 +544,78 @@ class BinASTParser : public BinASTParser
   JS::Result<ParseNode*> parseInterfaceUpdateExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceVariableDeclaration(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceVariableDeclarator(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
-      const Context& context);
+      const ListContext& context);
   JS::Result<ParseNode*> parseInterfaceWhileStatement(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceWithStatement(const size_t start,
                                                      const BinASTKind kind,
                                                      const BinASTFields& fields,
                                                      const Context& context);
   JS::Result<ParseNode*> parseInterfaceYieldExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
   JS::Result<ParseNode*> parseInterfaceYieldStarExpression(
       const size_t start, const BinASTKind kind, const BinASTFields& fields,
       const Context& context);
 
   // ----- String enums (by lexicographical order)
   JS::Result<typename BinASTParser<Tok>::AssertedDeclaredKind>
-  parseAssertedDeclaredKind(const Context& context);
+  parseAssertedDeclaredKind(const FieldContext& context);
   JS::Result<typename BinASTParser<Tok>::BinaryOperator> parseBinaryOperator(
-      const Context& context);
+      const FieldContext& context);
   JS::Result<typename BinASTParser<Tok>::CompoundAssignmentOperator>
-  parseCompoundAssignmentOperator(const Context& context);
+  parseCompoundAssignmentOperator(const FieldContext& context);
   JS::Result<typename BinASTParser<Tok>::UnaryOperator> parseUnaryOperator(
-      const Context& context);
+      const FieldContext& context);
   JS::Result<typename BinASTParser<Tok>::UpdateOperator> parseUpdateOperator(
-      const Context& context);
+      const FieldContext& context);
   JS::Result<typename BinASTParser<Tok>::VariableDeclarationKind>
-  parseVariableDeclarationKind(const Context& context);
+  parseVariableDeclarationKind(const FieldContext& context);
 
   // ----- Lists (by lexicographical order)
-  JS::Result<ParseNode*> parseArguments(const Context& context);
-  JS::Result<ListNode*> parseFunctionBody(const Context& context);
+  JS::Result<ParseNode*> parseArguments(const FieldContext& context);
+  JS::Result<ListNode*> parseFunctionBody(const FieldContext& context);
   JS::Result<Ok> parseListOfAssertedBoundName(AssertedScopeKind scopeKind,
-                                              const Context& context);
+                                              const FieldContext& context);
   JS::Result<Ok> parseListOfAssertedDeclaredName(AssertedScopeKind scopeKind,
-                                                 const Context& context);
+                                                 const FieldContext& context);
   JS::Result<Ok> parseListOfAssertedMaybePositionalParameterName(
       AssertedScopeKind scopeKind,
       MutableHandle<GCVector<JSAtom*>> positionalParams,
-      const Context& context);
-  JS::Result<ListNode*> parseListOfDirective(const Context& context);
-  JS::Result<ListNode*> parseListOfObjectProperty(const Context& context);
+      const FieldContext& context);
+  JS::Result<ListNode*> parseListOfDirective(const FieldContext& context);
+  JS::Result<ListNode*> parseListOfObjectProperty(const FieldContext& context);
   JS::Result<ListNode*> parseListOfOptionalExpressionOrSpreadElement(
-      const Context& context);
-  JS::Result<ListNode*> parseListOfParameter(const Context& context);
-  JS::Result<ListNode*> parseListOfStatement(const Context& context);
-  JS::Result<ListNode*> parseListOfSwitchCase(const Context& context);
+      const FieldContext& context);
+  JS::Result<ListNode*> parseListOfParameter(const FieldContext& context);
+  JS::Result<ListNode*> parseListOfStatement(const FieldContext& context);
+  JS::Result<ListNode*> parseListOfSwitchCase(const FieldContext& context);
   JS::Result<ListNode*> parseListOfVariableDeclarator(
-      ParseNodeKind declarationListKind, const Context& context);
+      ParseNodeKind declarationListKind, const FieldContext& context);
 
   // ----- Default values (by lexicographical order)
-  JS::Result<ParseNode*> parseOptionalBinding(const Context& context);
-  JS::Result<ParseNode*> parseOptionalBindingIdentifier(const Context& context);
+  JS::Result<ParseNode*> parseOptionalBinding(const FieldContext& context);
+  JS::Result<ParseNode*> parseOptionalBindingIdentifier(
+      const FieldContext& context);
   JS::Result<LexicalScopeNode*> parseOptionalCatchClause(
-      const Context& context);
-  JS::Result<ParseNode*> parseOptionalExpression(const Context& context);
+      const FieldContext& context);
+  JS::Result<ParseNode*> parseOptionalExpression(const FieldContext& context);
   JS::Result<ParseNode*> parseOptionalExpressionOrSpreadElement(
-      const Context& context);
+      const ListContext& context);
   JS::Result<ParseNode*> parseOptionalExpressionOrVariableDeclaration(
-      const Context& context);
-  JS::Result<ParseNode*> parseOptionalStatement(const Context& context);
+      const FieldContext& context);
+  JS::Result<ParseNode*> parseOptionalStatement(const FieldContext& context);
 };
 
 extern template class BinASTParser<BinASTTokenReaderContext>;
 extern template class BinASTParser<BinASTTokenReaderMultipart>;
 
 }  // namespace frontend
 }  // namespace js
 
--- a/js/src/frontend/BinASTParserPerTokenizer.cpp
+++ b/js/src/frontend/BinASTParserPerTokenizer.cpp
@@ -129,17 +129,17 @@ JS::Result<ParseNode*> BinASTParserPerTo
   ParseContext::VarScope varScope(cx_, &globalpc, usedNames_);
   if (!varScope.init(&globalpc)) {
     return cx_->alreadyReportedError();
   }
 
   MOZ_TRY(tokenizer_->readHeader());
 
   ParseNode* result(nullptr);
-  const Context topContext((RootContext()));
+  const auto topContext = RootContext();
   MOZ_TRY_VAR(result, asFinalParser()->parseProgram(topContext));
 
   mozilla::Maybe<GlobalScope::Data*> bindings =
       NewGlobalScopeData(cx_, varScope, alloc_, pc_);
   if (!bindings) {
     return cx_->alreadyReportedError();
   }
   globalsc->bindings = *bindings;
@@ -192,17 +192,17 @@ JS::Result<FunctionNode*> BinASTParserPe
   BINJS_TRY(lexicalScope.init(pc_));
   ListNode* params;
   ListNode* tmpBody;
   auto parseFunc = isExpr ? &FinalParser::parseFunctionExpressionContents
                           : &FinalParser::parseFunctionOrMethodContents;
 
   // Inject a toplevel context (i.e. no parent) to parse the lazy content.
   // In the future, we may move this to a more specific context.
-  const Context context((RootContext()));
+  const auto context = Context(RootContext());
   MOZ_TRY(
       (asFinalParser()->*parseFunc)(func->nargs(), &params, &tmpBody, context));
 
   uint32_t nargs = params->count();
 
   BINJS_TRY_DECL(lexicalScopeData,
                  NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
   BINJS_TRY_DECL(body, handler_.newLexicalScope(*lexicalScopeData, tmpBody));
--- a/js/src/frontend/BinASTTokenReaderContext.cpp
+++ b/js/src/frontend/BinASTTokenReaderContext.cpp
@@ -1359,23 +1359,23 @@ void BinASTTokenReaderContext::BitBuffer
 
 void BinASTTokenReaderContext::traceMetadata(JSTracer* trc) {
   if (metadata_) {
     metadata_->trace(trc);
   }
 }
 
 MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&>
-BinASTTokenReaderContext::raiseInvalidValue(const Context&) {
+BinASTTokenReaderContext::raiseInvalidValue() {
   errorReporter_->errorNoOffset(JSMSG_BINAST, "Invalid value");
   return cx_->alreadyReportedError();
 }
 
 MOZ_MUST_USE mozilla::GenericErrorResult<JS::Error&>
-BinASTTokenReaderContext::raiseNotInPrelude(const Context&) {
+BinASTTokenReaderContext::raiseNotInPrelude() {
   errorReporter_->errorNoOffset(JSMSG_BINAST, "Value is not in prelude");
   return cx_->alreadyReportedError();
 }
 
 struct ExtractBinASTInterfaceAndFieldMatcher {
   BinASTInterfaceAndField operator()(
       const BinASTTokenReaderBase::FieldContext& context) {
     return context.position;
@@ -1386,178 +1386,207 @@ struct ExtractBinASTInterfaceAndFieldMat
   }
   BinASTInterfaceAndField operator()(
       const BinASTTokenReaderBase::RootContext&) {
     MOZ_CRASH("The root context has no interface/field");
   }
 };
 
 struct TagReader {
-  using Context = BinASTTokenReaderBase::Context;
   using BitBuffer = BinASTTokenReaderContext::BitBuffer;
 
-  const Context& context;
   const HuffmanLookup bits;
   BitBuffer& bitBuffer;
   BinASTTokenReaderContext& owner;
-  TagReader(const Context& context, const HuffmanLookup bits,
-            BitBuffer& bitBuffer, BinASTTokenReaderContext& owner)
-      : context(context), bits(bits), bitBuffer(bitBuffer), owner(owner) {}
+  TagReader(const HuffmanLookup bits, BitBuffer& bitBuffer,
+            BinASTTokenReaderContext& owner)
+      : bits(bits), bitBuffer(bitBuffer), owner(owner) {}
   JS::Result<BinASTKind> operator()(
       const HuffmanTableIndexedSymbolsSum& specialized) {
     // We're entering either a single interface or a sum.
     const auto lookup = specialized.lookup(bits);
     bitBuffer.advanceBitBuffer<Compression::No>(lookup.key.bitLength);
     if (!lookup.value) {
-      return owner.raiseInvalidValue(context);
+      return owner.raiseInvalidValue();
     }
     return *lookup.value;
   }
   JS::Result<BinASTKind> operator()(
       const HuffmanTableIndexedSymbolsMaybeInterface& specialized) {
     // We're entering an optional interface.
     const auto lookup = specialized.lookup(bits);
     bitBuffer.advanceBitBuffer<Compression::No>(lookup.key.bitLength);
     if (!lookup.value) {
-      return owner.raiseInvalidValue(context);
+      return owner.raiseInvalidValue();
     }
     return *lookup.value;
   }
   template <typename Table>
   JS::Result<BinASTKind> operator()(const Table&) {
     MOZ_CRASH("Unreachable");
   }
 };
 
 JS::Result<BinASTKind> BinASTTokenReaderContext::readTagFromTable(
-    const Context& context) {
+    const BinASTInterfaceAndField& identity) {
   // Extract the table.
-  BinASTInterfaceAndField identity =
-      context.match(ExtractBinASTInterfaceAndFieldMatcher());
   const auto& table =
       dictionary.tableForField(NormalizedInterfaceAndField(identity));
   BINJS_MOZ_TRY_DECL(bits,
                      (bitBuffer.getHuffmanLookup<Compression::No>(*this)));
-  return table.match(TagReader(context, bits, bitBuffer, *this));
+  return table.match(TagReader(bits, bitBuffer, *this));
 }
 
 template <typename Table>
 JS::Result<typename Table::Contents>
-BinASTTokenReaderContext::readFieldFromTable(const Context& context) {
+BinASTTokenReaderContext::readFieldFromTable(
+    const BinASTInterfaceAndField& identity) {
   // Extract the table.
-  BinASTInterfaceAndField identity =
-      context.match(ExtractBinASTInterfaceAndFieldMatcher());
   const auto& table =
       dictionary.tableForField(NormalizedInterfaceAndField(identity));
   if (!table.is<Table>()) {
-    return raiseNotInPrelude(context);
+    return raiseNotInPrelude();
   }
   BINJS_MOZ_TRY_DECL(bits, bitBuffer.getHuffmanLookup<Compression::No>(*this));
   const auto lookup = table.as<Table>().lookup(bits);
 
   bitBuffer.advanceBitBuffer<Compression::No>(lookup.key.bitLength);
   if (!lookup.value) {
-    return raiseInvalidValue(context);
+    return raiseInvalidValue();
   }
   return *lookup.value;
 }
 
-JS::Result<bool> BinASTTokenReaderContext::readBool(const Context& context) {
-  return readFieldFromTable<HuffmanTableIndexedSymbolsBool>(context);
+JS::Result<bool> BinASTTokenReaderContext::readBool(
+    const FieldContext& context) {
+  return readFieldFromTable<HuffmanTableIndexedSymbolsBool>(context.position);
 }
 
 JS::Result<double> BinASTTokenReaderContext::readDouble(
-    const Context& context) {
-  return readFieldFromTable<HuffmanTableExplicitSymbolsF64>(context);
+    const FieldContext& context) {
+  return readFieldFromTable<HuffmanTableExplicitSymbolsF64>(context.position);
 }
 
 JS::Result<JSAtom*> BinASTTokenReaderContext::readMaybeAtom(
-    const Context& context) {
+    const FieldContext& context) {
   return readFieldFromTable<HuffmanTableIndexedSymbolsOptionalLiteralString>(
-      context);
+      context.position);
 }
 
-JS::Result<JSAtom*> BinASTTokenReaderContext::readAtom(const Context& context) {
-  return readFieldFromTable<HuffmanTableIndexedSymbolsLiteralString>(context);
+JS::Result<JSAtom*> BinASTTokenReaderContext::readAtom(
+    const FieldContext& context) {
+  return readFieldFromTable<HuffmanTableIndexedSymbolsLiteralString>(
+      context.position);
 }
 
 JS::Result<JSAtom*> BinASTTokenReaderContext::readMaybeIdentifierName(
-    const Context& context) {
+    const FieldContext& context) {
   return readMaybeAtom(context);
 }
 
 JS::Result<JSAtom*> BinASTTokenReaderContext::readIdentifierName(
-    const Context& context) {
+    const FieldContext& context) {
   return readAtom(context);
 }
 
 JS::Result<JSAtom*> BinASTTokenReaderContext::readPropertyKey(
-    const Context& context) {
+    const FieldContext& context) {
   return readAtom(context);
 }
 
-JS::Result<Ok> BinASTTokenReaderContext::readChars(Chars& out, const Context&) {
+JS::Result<Ok> BinASTTokenReaderContext::readChars(Chars& out,
+                                                   const FieldContext&) {
   return raiseError("readChars is not implemented in BinASTTokenReaderContext");
 }
 
 JS::Result<BinASTVariant> BinASTTokenReaderContext::readVariant(
-    const Context& context) {
-  BINJS_MOZ_TRY_DECL(
-      result,
-      readFieldFromTable<HuffmanTableIndexedSymbolsStringEnum>(context));
+    const ListContext& context) {
+  BINJS_MOZ_TRY_DECL(result,
+                     readFieldFromTable<HuffmanTableIndexedSymbolsStringEnum>(
+                         context.position));
+  return result;
+}
+
+JS::Result<BinASTVariant> BinASTTokenReaderContext::readVariant(
+    const FieldContext& context) {
+  BINJS_MOZ_TRY_DECL(result,
+                     readFieldFromTable<HuffmanTableIndexedSymbolsStringEnum>(
+                         context.position));
   return result;
 }
 
 JS::Result<uint32_t> BinASTTokenReaderContext::readUnsignedLong(
-    const Context& context) {
-  return readFieldFromTable<HuffmanTableExplicitSymbolsU32>(context);
+    const FieldContext& context) {
+  return readFieldFromTable<HuffmanTableExplicitSymbolsU32>(context.position);
 }
 
 JS::Result<BinASTTokenReaderBase::SkippableSubTree>
-BinASTTokenReaderContext::readSkippableSubTree(const Context&) {
+BinASTTokenReaderContext::readSkippableSubTree(const FieldContext&) {
   return raiseError("Not Yet Implemented");
 }
 
 JS::Result<Ok> BinASTTokenReaderContext::enterTaggedTuple(
     BinASTKind& tag, BinASTTokenReaderContext::BinASTFields&,
     const Context& context, AutoTaggedTuple& guard) {
   return context.match(
       [&tag](const BinASTTokenReaderBase::RootContext&) -> JS::Result<Ok> {
         // For the moment, the format hardcodes `Script` as root.
         tag = BinASTKind::Script;
         return Ok();
       },
-      [this, context,
-       &tag](const BinASTTokenReaderBase::ListContext&) -> JS::Result<Ok> {
+      [this, &tag](const BinASTTokenReaderBase::ListContext& asListContext)
+          -> JS::Result<Ok> {
         // This tuple is an element in a list we're currently reading.
-        MOZ_TRY_VAR(tag, readTagFromTable(context));
+        MOZ_TRY_VAR(tag, readTagFromTable(asListContext.position));
         return Ok();
       },
-      [this, context,
-       &tag](const BinASTTokenReaderBase::FieldContext& asFieldContext)
+      [this, &tag](const BinASTTokenReaderBase::FieldContext& asFieldContext)
           -> JS::Result<Ok> {
         // This tuple is the value of the field we're currently reading.
-        MOZ_TRY_VAR(tag, readTagFromTable(context));
+        MOZ_TRY_VAR(tag, readTagFromTable(asFieldContext.position));
         return Ok();
       });
 }
 
+JS::Result<Ok> BinASTTokenReaderContext::enterTaggedTuple(
+    BinASTKind& tag, BinASTTokenReaderContext::BinASTFields&,
+    const RootContext& context, AutoTaggedTuple& guard) {
+  // For the moment, the format hardcodes `Script` as root.
+  tag = BinASTKind::Script;
+  return Ok();
+}
+
+JS::Result<Ok> BinASTTokenReaderContext::enterTaggedTuple(
+    BinASTKind& tag, BinASTTokenReaderContext::BinASTFields&,
+    const ListContext& context, AutoTaggedTuple& guard) {
+  // This tuple is an element in a list we're currently reading.
+  MOZ_TRY_VAR(tag, readTagFromTable(context.position));
+  return Ok();
+}
+
+JS::Result<Ok> BinASTTokenReaderContext::enterTaggedTuple(
+    BinASTKind& tag, BinASTTokenReaderContext::BinASTFields&,
+    const FieldContext& context, AutoTaggedTuple& guard) {
+  // This tuple is the value of the field we're currently reading.
+  MOZ_TRY_VAR(tag, readTagFromTable(context.position));
+  return Ok();
+}
+
 JS::Result<Ok> BinASTTokenReaderContext::enterList(uint32_t& items,
-                                                   const Context& context,
+                                                   const ListContext& context,
                                                    AutoList& guard) {
-  const auto identity =
-      context.as<BinASTTokenReaderBase::ListContext>().content;
+  const auto identity = context.content;
   const auto& table = dictionary.tableForListLength(identity);
   BINJS_MOZ_TRY_DECL(bits, bitBuffer.getHuffmanLookup<Compression::No>(*this));
   const auto& tableForLookup =
       table.as<HuffmanTableExplicitSymbolsListLength>();
   const auto lookup = tableForLookup.lookup(bits);
   bitBuffer.advanceBitBuffer<Compression::No>(lookup.key.bitLength);
   if (!lookup.value) {
-    return raiseInvalidValue(context);
+    return raiseInvalidValue();
   }
   items = *lookup.value;
   return Ok();
 }
 
 void BinASTTokenReaderContext::AutoBase::init() { initialized_ = true; }
 
 BinASTTokenReaderContext::AutoBase::AutoBase(BinASTTokenReaderContext& reader)
--- a/js/src/frontend/BinASTTokenReaderContext.h
+++ b/js/src/frontend/BinASTTokenReaderContext.h
@@ -957,16 +957,19 @@ class MOZ_STACK_CLASS BinASTTokenReaderC
   using Base = BinASTTokenReaderBase;
 
  public:
   class AutoList;
   class AutoTaggedTuple;
 
   using CharSlice = BinaryASTSupport::CharSlice;
   using Context = BinASTTokenReaderBase::Context;
+  using RootContext = BinASTTokenReaderBase::RootContext;
+  using ListContext = BinASTTokenReaderBase::ListContext;
+  using FieldContext = BinASTTokenReaderBase::FieldContext;
 
   // This implementation of `BinASTFields` is effectively `void`, as the format
   // does not embed field information.
   class BinASTFields {
    public:
     explicit BinASTFields(JSContext*) {}
   };
   using Chars = CharSlice;
@@ -1104,65 +1107,64 @@ class MOZ_STACK_CLASS BinASTTokenReaderC
   // Reading will return an error either in case of I/O error or in case of
   // a format problem. Reading if an exception in pending is an error and
   // will cause assertion failures. Do NOT attempt to read once an exception
   // has been cleared: the token reader does NOT support recovery, by design.
 
   /**
    * Read a single `true | false` value.
    */
-  MOZ_MUST_USE JS::Result<bool> readBool(const Context&);
+  MOZ_MUST_USE JS::Result<bool> readBool(const FieldContext&);
 
   /**
    * Read a single `number` value.
    */
-  MOZ_MUST_USE JS::Result<double> readDouble(const Context&);
+  MOZ_MUST_USE JS::Result<double> readDouble(const FieldContext&);
 
   /**
    * Read a single `string | null` value.
    *
    * Fails if that string is not valid UTF-8.
    */
-  MOZ_MUST_USE JS::Result<JSAtom*> readMaybeAtom(const Context&);
-  MOZ_MUST_USE JS::Result<JSAtom*> readAtom(const Context&);
+  MOZ_MUST_USE JS::Result<JSAtom*> readMaybeAtom(const FieldContext&);
+  MOZ_MUST_USE JS::Result<JSAtom*> readAtom(const FieldContext&);
 
   /**
    * Read a single IdentifierName value.
    */
-  MOZ_MUST_USE JS::Result<JSAtom*> readMaybeIdentifierName(const Context&);
-  MOZ_MUST_USE JS::Result<JSAtom*> readIdentifierName(const Context&);
+  MOZ_MUST_USE JS::Result<JSAtom*> readMaybeIdentifierName(const FieldContext&);
+  MOZ_MUST_USE JS::Result<JSAtom*> readIdentifierName(const FieldContext&);
 
   /**
    * Read a single PropertyKey value.
    */
-  MOZ_MUST_USE JS::Result<JSAtom*> readPropertyKey(const Context&);
+  MOZ_MUST_USE JS::Result<JSAtom*> readPropertyKey(const FieldContext&);
 
   /**
    * Read a single `string | null` value.
    *
    * MAY check if that string is not valid UTF-8.
    */
-  MOZ_MUST_USE JS::Result<Ok> readChars(Chars&, const Context&);
+  MOZ_MUST_USE JS::Result<Ok> readChars(Chars&, const FieldContext&);
 
   /**
    * Read a single `BinASTVariant | null` value.
    */
-  MOZ_MUST_USE JS::Result<mozilla::Maybe<BinASTVariant>> readMaybeVariant(
-      const Context&);
-  MOZ_MUST_USE JS::Result<BinASTVariant> readVariant(const Context&);
+  MOZ_MUST_USE JS::Result<BinASTVariant> readVariant(const ListContext&);
+  MOZ_MUST_USE JS::Result<BinASTVariant> readVariant(const FieldContext&);
 
   /**
    * Read over a single `[Skippable]` subtree value.
    *
    * This does *not* attempt to parse the subtree itself. Rather, the
    * returned `SkippableSubTree` contains the necessary information
    * to parse/tokenize the subtree at a later stage
    */
   MOZ_MUST_USE JS::Result<SkippableSubTree> readSkippableSubTree(
-      const Context&);
+      const FieldContext&);
 
   // --- Composite values.
   //
   // The underlying format does NOT allows for a `null` composite value.
   //
   // Reading will return an error either in case of I/O error or in case of
   // a format problem. Reading from a poisoned tokenizer is an error and
   // will cause assertion failures.
@@ -1174,17 +1176,17 @@ class MOZ_STACK_CLASS BinASTTokenReaderC
    * @param guard (OUT) A guard, ensuring that we read the list correctly.
    *
    * The `guard` is dedicated to ensuring that reading the list has consumed
    * exactly all the bytes from that list. The `guard` MUST therefore be
    * destroyed at the point where the caller has reached the end of the list.
    * If the caller has consumed too few/too many bytes, this will be reported
    * in the call go `guard.done()`.
    */
-  MOZ_MUST_USE JS::Result<Ok> enterList(uint32_t& length, const Context&,
+  MOZ_MUST_USE JS::Result<Ok> enterList(uint32_t& length, const ListContext&,
                                         AutoList& guard);
 
   /**
    * Start reading a tagged tuple.
    *
    * @param tag (OUT) The tag of the tuple.
    * @param fields Ignored, provided for API compatibility.
    * @param guard (OUT) A guard, ensuring that we read the tagged tuple
@@ -1196,39 +1198,49 @@ class MOZ_STACK_CLASS BinASTTokenReaderC
    * If the caller has consumed too few/too many bytes, this will be reported
    * in the call go `guard.done()`.
    *
    * @return out If the header of the tuple is invalid.
    */
   MOZ_MUST_USE JS::Result<Ok> enterTaggedTuple(
       BinASTKind& tag, BinASTTokenReaderContext::BinASTFields& fields,
       const Context&, AutoTaggedTuple& guard);
+  MOZ_MUST_USE JS::Result<Ok> enterTaggedTuple(
+      BinASTKind& tag, BinASTTokenReaderContext::BinASTFields& fields,
+      const RootContext&, AutoTaggedTuple& guard);
+  MOZ_MUST_USE JS::Result<Ok> enterTaggedTuple(
+      BinASTKind& tag, BinASTTokenReaderContext::BinASTFields& fields,
+      const ListContext&, AutoTaggedTuple& guard);
+  MOZ_MUST_USE JS::Result<Ok> enterTaggedTuple(
+      BinASTKind& tag, BinASTTokenReaderContext::BinASTFields& fields,
+      const FieldContext&, AutoTaggedTuple& guard);
 
   /**
    * Read a single unsigned long.
    */
-  MOZ_MUST_USE JS::Result<uint32_t> readUnsignedLong(const Context&);
+  MOZ_MUST_USE JS::Result<uint32_t> readUnsignedLong(const FieldContext&);
   MOZ_MUST_USE JS::Result<uint32_t> readUnpackedLong();
 
  private:
-  MOZ_MUST_USE JS::Result<BinASTKind> readTagFromTable(const Context&);
+  MOZ_MUST_USE JS::Result<BinASTKind> readTagFromTable(
+      const BinASTInterfaceAndField&);
 
   template <typename Table>
   MOZ_MUST_USE JS::Result<typename Table::Contents> readFieldFromTable(
-      const Context&);
+      const BinASTInterfaceAndField&);
 
   /**
    * Report an "invalid value error".
    */
-  MOZ_MUST_USE ErrorResult<JS::Error&> raiseInvalidValue(const Context&);
+  MOZ_MUST_USE ErrorResult<JS::Error&> raiseInvalidValue();
 
   /**
    * Report a "value not in prelude".
    */
-  MOZ_MUST_USE ErrorResult<JS::Error&> raiseNotInPrelude(const Context&);
+  MOZ_MUST_USE ErrorResult<JS::Error&> raiseNotInPrelude();
 
  private:
   /**
    * Read a single uint32_t.
    */
   template <Compression compression>
   MOZ_MUST_USE JS::Result<uint32_t> readVarU32();
 
--- a/js/src/frontend/BinASTTokenReaderMultipart.cpp
+++ b/js/src/frontend/BinASTTokenReaderMultipart.cpp
@@ -216,17 +216,17 @@ JS::Result<Ok> BinASTTokenReaderMultipar
 }
 
 void BinASTTokenReaderMultipart::traceMetadata(JSTracer* trc) {
   if (metadata_) {
     metadata_->trace(trc);
   }
 }
 
-JS::Result<bool> BinASTTokenReaderMultipart::readBool(const Context&) {
+JS::Result<bool> BinASTTokenReaderMultipart::readBool(const FieldContext&) {
   updateLatestKnownGood();
   BINJS_MOZ_TRY_DECL(byte, readByte());
 
   switch (byte) {
     case 0:
       return false;
     case 1:
       return true;
@@ -236,17 +236,17 @@ JS::Result<bool> BinASTTokenReaderMultip
       return raiseError("Invalid boolean value");
   }
 }
 
 // Nullable doubles (little-endian)
 //
 // NULL_FLOAT_REPRESENTATION (signaling NaN) => null
 // anything other 64 bit sequence => IEEE-764 64-bit floating point number
-JS::Result<double> BinASTTokenReaderMultipart::readDouble(const Context&) {
+JS::Result<double> BinASTTokenReaderMultipart::readDouble(const FieldContext&) {
   updateLatestKnownGood();
 
   uint8_t bytes[8];
   MOZ_ASSERT(sizeof(bytes) == sizeof(double));
   MOZ_TRY(
       readBuf(reinterpret_cast<uint8_t*>(bytes), mozilla::ArrayLength(bytes)));
 
   // Decode little-endian.
@@ -257,77 +257,77 @@ JS::Result<double> BinASTTokenReaderMult
   }
 
   // Canonicalize NaN, just to make sure another form of signalling NaN
   // doesn't slip past us.
   return JS::CanonicalizeNaN(mozilla::BitwiseCast<double>(asInt));
 }
 
 // A single atom is represented as an index into the table of strings.
-JS::Result<JSAtom*> BinASTTokenReaderMultipart::readMaybeAtom(const Context&) {
+JS::Result<JSAtom*> BinASTTokenReaderMultipart::readMaybeAtom(
+    const FieldContext&) {
   updateLatestKnownGood();
   BINJS_MOZ_TRY_DECL(index, readInternalUint32());
 
   if (index >= metadata_->numStrings()) {
     return raiseError("Invalid index to strings table");
   }
   return metadata_->getAtom(index);
 }
 
 JS::Result<JSAtom*> BinASTTokenReaderMultipart::readAtom(
-    const Context& context) {
+    const FieldContext& context) {
   BINJS_MOZ_TRY_DECL(maybe, readMaybeAtom(context));
 
   if (!maybe) {
     return raiseError("Empty string");
   }
 
   return maybe;
 }
 
 JS::Result<JSAtom*> BinASTTokenReaderMultipart::readMaybeIdentifierName(
-    const Context& context) {
+    const FieldContext& context) {
   BINJS_MOZ_TRY_DECL(result, readMaybeAtom(context));
   if (result) {
     if (!IsIdentifier(result)) {
       return raiseError("Invalid identifier");
     }
   }
   return result;
 }
 
 JS::Result<JSAtom*> BinASTTokenReaderMultipart::readIdentifierName(
-    const Context& context) {
+    const FieldContext& context) {
   BINJS_MOZ_TRY_DECL(result, readAtom(context));
   if (!IsIdentifier(result)) {
     return raiseError("Invalid identifier");
   }
   return result;
 }
 
 JS::Result<JSAtom*> BinASTTokenReaderMultipart::readPropertyKey(
-    const Context& context) {
+    const FieldContext& context) {
   return readAtom(context);
 }
 
 JS::Result<Ok> BinASTTokenReaderMultipart::readChars(Chars& out,
-                                                     const Context&) {
+                                                     const FieldContext&) {
   updateLatestKnownGood();
   BINJS_MOZ_TRY_DECL(index, readInternalUint32());
 
   if (index >= metadata_->numStrings()) {
     return raiseError("Invalid index to strings table for string enum");
   }
 
   out = metadata_->getSlice(index);
   return Ok();
 }
 
-JS::Result<BinASTVariant> BinASTTokenReaderMultipart::readVariant(
-    const Context&) {
+JS::Result<BinASTVariant> BinASTTokenReaderMultipart::readVariant() {
   updateLatestKnownGood();
   BINJS_MOZ_TRY_DECL(index, readInternalUint32());
 
   if (index >= metadata_->numStrings()) {
     return raiseError("Invalid index to strings table for string enum");
   }
 
   auto variantsPtr = variantsTable_.lookupForAdd(index);
@@ -352,17 +352,17 @@ JS::Result<BinASTVariant> BinASTTokenRea
   if (!variantsTable_.add(variantsPtr, index, *variant)) {
     return raiseOOM();
   }
 
   return *variant;
 }
 
 JS::Result<BinASTTokenReaderBase::SkippableSubTree>
-BinASTTokenReaderMultipart::readSkippableSubTree(const Context&) {
+BinASTTokenReaderMultipart::readSkippableSubTree(const FieldContext&) {
   updateLatestKnownGood();
   BINJS_MOZ_TRY_DECL(byteLen, readInternalUint32());
 
   if (current_ + byteLen > stop_ || current_ + byteLen < current_) {
     return raiseError("Invalid byte length in readSkippableSubTree");
   }
 
   const auto start = offset();
@@ -385,25 +385,41 @@ JS::Result<Ok> BinASTTokenReaderMultipar
 
   tag = metadata_->getBinASTKind(index);
 
   // Enter the body.
   guard.init();
   return Ok();
 }
 
+JS::Result<Ok> BinASTTokenReaderMultipart::enterTaggedTuple(
+    BinASTKind& tag, BinASTTokenReaderMultipart::BinASTFields& fields,
+    const RootContext& context, AutoTaggedTuple& guard) {
+  return enterTaggedTuple(tag, fields, Context(context), guard);
+}
+JS::Result<Ok> BinASTTokenReaderMultipart::enterTaggedTuple(
+    BinASTKind& tag, BinASTTokenReaderMultipart::BinASTFields& fields,
+    const ListContext& context, AutoTaggedTuple& guard) {
+  return enterTaggedTuple(tag, fields, Context(context), guard);
+}
+JS::Result<Ok> BinASTTokenReaderMultipart::enterTaggedTuple(
+    BinASTKind& tag, BinASTTokenReaderMultipart::BinASTFields& fields,
+    const FieldContext& context, AutoTaggedTuple& guard) {
+  return enterTaggedTuple(tag, fields, Context(context), guard);
+}
+
 // List:
 //
 // - uint32_t number of items;
 // - contents (specified by higher-level grammar);
 //
 // The total byte length of `number of items` + `contents` must be `byte
 // length`.
 JS::Result<Ok> BinASTTokenReaderMultipart::enterList(uint32_t& items,
-                                                     const Context&,
+                                                     const ListContext&,
                                                      AutoList& guard) {
   guard.init();
 
   MOZ_TRY_VAR(items, readInternalUint32());
 
   return Ok();
 }
 
--- a/js/src/frontend/BinASTTokenReaderMultipart.h
+++ b/js/src/frontend/BinASTTokenReaderMultipart.h
@@ -33,16 +33,19 @@ namespace frontend {
 class MOZ_STACK_CLASS BinASTTokenReaderMultipart
     : public BinASTTokenReaderBase {
  public:
   class AutoList;
   class AutoTaggedTuple;
 
   using CharSlice = BinaryASTSupport::CharSlice;
   using Context = BinASTTokenReaderBase::Context;
+  using RootContext = BinASTTokenReaderBase::RootContext;
+  using ListContext = BinASTTokenReaderBase::ListContext;
+  using FieldContext = BinASTTokenReaderBase::FieldContext;
 
   // This implementation of `BinASTFields` is effectively `void`, as the format
   // does not embed field information.
   class BinASTFields {
    public:
     explicit BinASTFields(JSContext*) {}
   };
   using Chars = CharSlice;
@@ -79,65 +82,74 @@ class MOZ_STACK_CLASS BinASTTokenReaderM
   // Reading will return an error either in case of I/O error or in case of
   // a format problem. Reading if an exception in pending is an error and
   // will cause assertion failures. Do NOT attempt to read once an exception
   // has been cleared: the token reader does NOT support recovery, by design.
 
   /**
    * Read a single `true | false` value.
    */
-  MOZ_MUST_USE JS::Result<bool> readBool(const Context&);
+  MOZ_MUST_USE JS::Result<bool> readBool(const FieldContext&);
 
   /**
    * Read a single `number` value.
    */
-  MOZ_MUST_USE JS::Result<double> readDouble(const Context&);
+  MOZ_MUST_USE JS::Result<double> readDouble(const FieldContext&);
 
   /**
    * Read a single `string | null` value.
    *
    * Fails if that string is not valid UTF-8.
    */
-  MOZ_MUST_USE JS::Result<JSAtom*> readMaybeAtom(const Context&);
-  MOZ_MUST_USE JS::Result<JSAtom*> readAtom(const Context&);
+  MOZ_MUST_USE JS::Result<JSAtom*> readMaybeAtom(const FieldContext&);
+  MOZ_MUST_USE JS::Result<JSAtom*> readAtom(const FieldContext&);
 
   /**
    * Read a single IdentifierName value.
    */
-  MOZ_MUST_USE JS::Result<JSAtom*> readMaybeIdentifierName(const Context&);
-  MOZ_MUST_USE JS::Result<JSAtom*> readIdentifierName(const Context&);
+  MOZ_MUST_USE JS::Result<JSAtom*> readMaybeIdentifierName(const FieldContext&);
+  MOZ_MUST_USE JS::Result<JSAtom*> readIdentifierName(const FieldContext&);
 
   /**
    * Read a single PropertyKey value.
    */
-  MOZ_MUST_USE JS::Result<JSAtom*> readPropertyKey(const Context&);
+  MOZ_MUST_USE JS::Result<JSAtom*> readPropertyKey(const FieldContext&);
 
   /**
    * Read a single `string | null` value.
    *
    * MAY check if that string is not valid UTF-8.
    */
-  MOZ_MUST_USE JS::Result<Ok> readChars(Chars&, const Context&);
+  MOZ_MUST_USE JS::Result<Ok> readChars(Chars&, const FieldContext&);
 
   /**
    * Read a single `BinASTVariant | null` value.
    */
-  MOZ_MUST_USE JS::Result<mozilla::Maybe<BinASTVariant>> readMaybeVariant(
-      const Context&);
-  MOZ_MUST_USE JS::Result<BinASTVariant> readVariant(const Context&);
+ private:
+  MOZ_MUST_USE JS::Result<BinASTVariant> readVariant();
+
+ public:
+  MOZ_MUST_USE JS::Result<BinASTVariant> readVariant(
+      const ListContext& context) {
+    return readVariant();
+  }
+  MOZ_MUST_USE JS::Result<BinASTVariant> readVariant(
+      const FieldContext& context) {
+    return readVariant();
+  }
 
   /**
    * Read over a single `[Skippable]` subtree value.
    *
    * This does *not* attempt to parse the subtree itself. Rather, the
    * returned `SkippableSubTree` contains the necessary information
    * to parse/tokenize the subtree at a later stage
    */
   MOZ_MUST_USE JS::Result<SkippableSubTree> readSkippableSubTree(
-      const Context&);
+      const FieldContext&);
 
   // --- Composite values.
   //
   // The underlying format does NOT allows for a `null` composite value.
   //
   // Reading will return an error either in case of I/O error or in case of
   // a format problem. Reading from a poisoned tokenizer is an error and
   // will cause assertion failures.
@@ -149,17 +161,17 @@ class MOZ_STACK_CLASS BinASTTokenReaderM
    * @param guard (OUT) A guard, ensuring that we read the list correctly.
    *
    * The `guard` is dedicated to ensuring that reading the list has consumed
    * exactly all the bytes from that list. The `guard` MUST therefore be
    * destroyed at the point where the caller has reached the end of the list.
    * If the caller has consumed too few/too many bytes, this will be reported
    * in the call go `guard.done()`.
    */
-  MOZ_MUST_USE JS::Result<Ok> enterList(uint32_t& length, const Context&,
+  MOZ_MUST_USE JS::Result<Ok> enterList(uint32_t& length, const ListContext&,
                                         AutoList& guard);
 
   /**
    * Start reading a tagged tuple.
    *
    * @param tag (OUT) The tag of the tuple.
    * @param fields Ignored, provided for API compatibility.
    * @param guard (OUT) A guard, ensuring that we read the tagged tuple
@@ -171,21 +183,30 @@ class MOZ_STACK_CLASS BinASTTokenReaderM
    * If the caller has consumed too few/too many bytes, this will be reported
    * in the call go `guard.done()`.
    *
    * @return out If the header of the tuple is invalid.
    */
   MOZ_MUST_USE JS::Result<Ok> enterTaggedTuple(
       BinASTKind& tag, BinASTTokenReaderMultipart::BinASTFields& fields,
       const Context&, AutoTaggedTuple& guard);
+  MOZ_MUST_USE JS::Result<Ok> enterTaggedTuple(
+      BinASTKind& tag, BinASTTokenReaderMultipart::BinASTFields& fields,
+      const RootContext&, AutoTaggedTuple& guard);
+  MOZ_MUST_USE JS::Result<Ok> enterTaggedTuple(
+      BinASTKind& tag, BinASTTokenReaderMultipart::BinASTFields& fields,
+      const ListContext&, AutoTaggedTuple& guard);
+  MOZ_MUST_USE JS::Result<Ok> enterTaggedTuple(
+      BinASTKind& tag, BinASTTokenReaderMultipart::BinASTFields& fields,
+      const FieldContext&, AutoTaggedTuple& guard);
 
   /**
    * Read a single unsigned long.
    */
-  MOZ_MUST_USE JS::Result<uint32_t> readUnsignedLong(const Context&) {
+  MOZ_MUST_USE JS::Result<uint32_t> readUnsignedLong(const FieldContext&) {
     return readInternalUint32();
   }
 
  private:
   /**
    * Read a single uint32_t.
    */
   MOZ_MUST_USE JS::Result<uint32_t> readInternalUint32();
--- a/js/src/frontend/binast/src/main.rs
+++ b/js/src/frontend/binast/src/main.rs
@@ -553,27 +553,111 @@ const INTERFACE_PARAMS: &str =
 /// Fixed arguments of interface method.
 const INTERFACE_ARGS: &str =
     "start, kind, fields";
 
 /// The name of the toplevel interface for the script.
 const TOPLEVEL_INTERFACE: &str =
     "Program";
 
+/// In which context an interface appears.
+#[derive(Clone, Debug, PartialEq)]
+struct LookupContext {
+    /// In root of parsing.
+    in_root: bool,
+
+    /// In list element.
+    in_list: bool,
+
+    /// In interface field.
+    in_field: bool,
+}
+impl LookupContext {
+    fn empty() -> Self {
+        Self {
+            in_root: false,
+            in_list: false,
+            in_field: false,
+        }
+    }
+
+    fn root() -> Self {
+        Self {
+            in_root: true,
+            in_list: false,
+            in_field: false,
+        }
+    }
+
+    fn list() -> Self {
+        Self {
+            in_root: false,
+            in_list: true,
+            in_field: false,
+        }
+    }
+
+    fn field() -> Self {
+        Self {
+            in_root: false,
+            in_list: false,
+            in_field: true,
+        }
+    }
+
+    fn is_root(&self) -> bool {
+        self.in_root && !self.in_list && !self.in_field
+    }
+
+    fn is_list(&self) -> bool {
+        !self.in_root && self.in_list && !self.in_field
+    }
+
+    fn is_field(&self) -> bool {
+        !self.in_root && !self.in_list && self.in_field
+    }
+
+    fn is_field_and_list(&self) -> bool {
+        !self.in_root && self.in_list && self.in_field
+    }
+
+    fn is_field_and_root(&self) -> bool {
+        self.in_root && !self.in_list && self.in_field
+    }
+
+    fn is_single(&self) -> bool {
+        self.is_root() || self.is_list() || self.is_field()
+    }
+
+    fn is_valid_double(&self) -> bool {
+        self.is_field_and_root() || self.is_field_and_list()
+    }
+
+    fn add(&mut self, rhs: Self) {
+        self.in_root |= rhs.in_root;
+        self.in_list |= rhs.in_list;
+        self.in_field |= rhs.in_field;
+    }
+}
+
+type ContextMap = HashMap<Rc<String>, LookupContext>;
+
 /// The actual exporter.
 struct CPPExporter {
     /// The syntax to export.
     syntax: Spec,
 
     /// Rules, as specified in yaml.
     rules: GlobalRules,
 
     /// Reference graph of the method call.
     refgraph: ReferenceGraph,
 
+    context_map: ContextMap,
+
     /// All parsers of lists.
     list_parsers_to_generate: Vec<ListParserData>,
 
     /// All parsers of options.
     option_parsers_to_generate: Vec<OptionParserData>,
 
     /// A subset of `list_parsers_to_generate` guaranteed to have
     /// a single representative for each list type, regardless
@@ -680,28 +764,50 @@ impl CPPExporter {
                 (string, expanded)
             })
             .collect();
 
         // This is just a placeholder to instantiate the CPPExporter struct.
         // The field will be overwritten later in generate_reference_graph.
         let refgraph = ReferenceGraph::new();
 
+        let context_map = HashMap::new();
+
         CPPExporter {
             syntax,
             rules,
             refgraph,
+            context_map,
             list_parsers_to_generate,
             option_parsers_to_generate,
             canonical_list_parsers,
             variants_by_symbol,
             enum_types,
         }
     }
 
+    /// Return NamedType for given NodeName.
+    /// Panic if NodeName is not NamedType
+    fn get_named_implementation(&self, name: &NodeName) -> NamedType {
+        if let Some(NamedType::Typedef(ref typedef)) = self.syntax.get_type_by_name(name) {
+            assert!(typedef.is_optional());
+            if let TypeSpec::NamedType(ref named) = *typedef.spec() {
+                self.syntax.get_type_by_name(named)
+                    .unwrap_or_else(|| panic!("Internal error: Could not find type {}, which should have been generated.", named.to_str()))
+            } else {
+                panic!("Internal error: In {}, type {:?} should have been a named type",
+                       name.to_str(),
+                       typedef);
+            }
+        } else {
+            panic!("Internal error: In {}, there should be a type with that name",
+                   name.to_str());
+        }
+    }
+
     /// Generate a reference graph of methods.
     fn generate_reference_graph(&mut self) {
         let mut refgraph = ReferenceGraph::new();
 
         // FIXME: Reflect `replace` rule in yaml file for each interface to
         //        the reference (bug 1504595).
 
         // 1. Typesums
@@ -786,31 +892,17 @@ impl CPPExporter {
             let mut edges: HashSet<Rc<String>> = HashSet::new();
             edges.insert(parser.elements.to_rc_string().clone());
             refgraph.insert(name.to_rc_string().clone(), edges);
         }
 
         // 5. Optional values
         for parser in &self.option_parsers_to_generate {
             let mut edges: HashSet<Rc<String>> = HashSet::new();
-            let named_implementation =
-                if let Some(NamedType::Typedef(ref typedef)) = self.syntax.get_type_by_name(&parser.name) {
-                    assert!(typedef.is_optional());
-                    if let TypeSpec::NamedType(ref named) = *typedef.spec() {
-                        self.syntax.get_type_by_name(named)
-                            .unwrap_or_else(|| panic!("Internal error: Could not find type {}, which should have been generated.", named.to_str()))
-                    } else {
-                        panic!("Internal error: In {}, type {:?} should have been a named type",
-                               parser.name.to_str(),
-                               typedef);
-                    }
-                } else {
-                    panic!("Internal error: In {}, there should be a type with that name",
-                           parser.name.to_str());
-                };
+            let named_implementation = self.get_named_implementation(&parser.name);
             match named_implementation {
                 NamedType::Interface(_) => {
                     edges.insert(Rc::new(format!("Interface{}", parser.elements.to_string())));
                 },
                 NamedType::Typedef(ref type_) => {
                     match type_.spec() {
                         &TypeSpec::TypeSum(_) => {
                             edges.insert(Rc::new(format!("Sum{}", parser.elements.to_string())));
@@ -831,16 +923,156 @@ impl CPPExporter {
     }
 
     /// Trace the reference graph from the node with `name and mark all nodes
     /// as used. `name` is the name of the method, without leading "parse".
     fn trace(&mut self, name: Rc<String>) {
         self.refgraph.trace(name)
     }
 
+    /// Collect context information for each interface to determine
+    /// which *Context type each method should receive.
+    fn collect_context(&mut self) {
+        fn add_context(map: &mut ContextMap, name: Rc<String>,
+                       context: LookupContext) {
+            let entry = map.entry(name).or_insert(LookupContext::empty());
+            (*entry).add(context);
+        }
+
+        // 1. Root
+        add_context(&mut self.context_map,
+                    Rc::new("Program".to_string()), LookupContext::root());
+        add_context(&mut self.context_map,
+                    Rc::new("FunctionExpressionContents".to_string()),
+                    LookupContext::root());
+        add_context(&mut self.context_map,
+                    Rc::new("FunctionOrMethodContents".to_string()),
+                    LookupContext::root());
+
+        // 2. Interface fields
+        // XXX => XXX.field
+        for (name, interface) in self.syntax.interfaces_by_name() {
+            let inner_prefix = "Interface";
+            let inner_name = Rc::new(format!("{}{}", inner_prefix, name));
+            if !self.refgraph.is_used(inner_name) {
+                continue;
+            }
+
+            for field in interface.contents().fields() {
+                match field.type_().get_primitive(&self.syntax) {
+                    Some(IsNullable { is_nullable: _,
+                                      content: Primitive::Interface(_) })
+                        | None => {
+                            let typename = TypeName::type_(field.type_());
+                            add_context(&mut self.context_map,
+                                        Rc::new(typename),
+                                        LookupContext::field());
+                        }
+                    _ => {}
+                }
+            }
+        }
+
+        // 3. List contents
+        // ListXXX => XXX
+        for parser in &self.list_parsers_to_generate {
+            if !self.refgraph.is_used(parser.name.to_rc_string().clone()) {
+                continue;
+            }
+
+            add_context(&mut self.context_map,
+                        Rc::new(parser.elements.to_class_cases()),
+                        LookupContext::list());
+        }
+
+        fn propagate_context(map: &mut ContextMap, from: Rc<String>,
+                             to: Rc<String>) {
+            let opt_context = match map.get(&from) {
+                Some(opt_context) => {
+                    opt_context.clone()
+                }
+                _ => {
+                    return;
+                }
+            };
+            let entry = map.entry(to).or_insert(LookupContext::empty());
+            (*entry).add(opt_context);
+        }
+
+        // 4. Propagate Optional
+        // OptionalXXX => XXX
+        for parser in &self.option_parsers_to_generate {
+            if !self.refgraph.is_used(parser.name.to_rc_string().clone()) {
+                continue;
+            }
+
+            let named_implementation = self.get_named_implementation(&parser.name);
+            match named_implementation {
+                NamedType::Interface(_) => {
+                    propagate_context(&mut self.context_map,
+                                      Rc::new(parser.name.to_class_cases()),
+                                      Rc::new(format!("Interface{}", parser.elements.to_class_cases())));
+                },
+                NamedType::Typedef(ref type_) => {
+                    match type_.spec() {
+                        &TypeSpec::TypeSum(_) => {
+                            propagate_context(&mut self.context_map,
+                                              Rc::new(parser.name.to_class_cases()),
+                                              Rc::new(format!("Sum{}", parser.elements.to_class_cases())));
+                        },
+                        _ => {}
+                    }
+                },
+                _ => {}
+            }
+        }
+
+        // 5. Propagate Sum
+        // XXX => SumXXX
+        // SumXXX => each arm
+        let sums_of_interfaces = self.syntax.resolved_sums_of_interfaces_by_name();
+        for (name, nodes) in sums_of_interfaces {
+            if !self.refgraph.is_used(name.to_rc_string().clone()) {
+                continue;
+            }
+
+            propagate_context(
+                &mut self.context_map,
+                Rc::new(name.to_class_cases()),
+                Rc::new(format!("Sum{}", name.to_class_cases())));
+
+            for node in nodes {
+                propagate_context(
+                    &mut self.context_map,
+                    Rc::new(format!("Sum{}", name.to_class_cases())),
+                    Rc::new(format!("Interface{}", node.to_class_cases())));
+            }
+        }
+
+        // 6. Propagate Interface
+        // XXX => InterfaceXXX
+        // InterfaceXXX => XXX
+        for (name, _) in self.syntax.interfaces_by_name() {
+            let inner_prefix = "Interface";
+            let inner_name = Rc::new(format!("{}{}", inner_prefix, name));
+            if !self.refgraph.is_used(inner_name) {
+                continue;
+            }
+
+            propagate_context(
+                &mut self.context_map,
+                Rc::new(name.to_class_cases()),
+                Rc::new(format!("Interface{}", name.to_class_cases())));
+            propagate_context(
+                &mut self.context_map,
+                Rc::new(format!("Interface{}", name.to_class_cases())),
+                Rc::new(name.to_class_cases()));
+        }
+    }
+
 // ----- Generating the header
 
     /// Get the type representing a success for parsing this node.
     fn get_type_ok(&self, name: &NodeName) -> Rc<String> {
         // enum has its own rule.
         if self.enum_types.contains_key(name) {
             return self.enum_types.get(name).unwrap().clone();
         }
@@ -861,16 +1093,44 @@ impl CPPExporter {
         if let Some(type_ok) = rules_for_this_interface.type_ok {
             if type_ok.as_str() == "Ok" {
                 return Rc::new("Ok()".to_string());
             }
         }
         self.rules.parser_default_value.clone()
     }
 
+    fn get_context_param(&self, name: &NodeName, prefix: &str) -> String {
+        let context = match self.context_map.get(&Rc::new(format!("{}{}", prefix, name.to_rc_string()))) {
+            Some(context) => {
+                context.clone()
+            }
+            _ => {
+                panic!("{}{} doesn't have context", prefix, name.to_rc_string());
+            }
+        };
+        if context.is_root() {
+            return "const RootContext& context".to_string();
+        }
+        if context.is_list() {
+            return "const ListContext& context".to_string();
+        }
+        if context.is_field() {
+            return "const FieldContext& context".to_string();
+        }
+        if context.is_field_and_list() {
+            return "const Context& context".to_string();
+        }
+        if context.is_field_and_root() {
+            return "const Context& context".to_string();
+        }
+
+        panic!("unexpected context");
+    }
+
     fn get_method_signature(&self, name: &NodeName, prefix: &str, args: &str,
                             extra_params: &Option<Rc<String>>) -> String {
         let type_ok = self.get_type_ok(name);
         let kind = name.to_class_cases();
         let extra = match extra_params {
             Some(s) => {
                 format!("{}\n{}",
                         if args.len() > 0 {
@@ -891,17 +1151,17 @@ impl CPPExporter {
             kind = kind,
             args = args,
             extra = extra,
             before_context = if args.len() > 0 || extra_params.is_some() {
                 ", "
             } else {
                 ""
             },
-            context = "const Context& context",
+            context = self.get_context_param(name, prefix),
         )
     }
 
     fn get_method_definition_start(&self, name: &NodeName, prefix: &str, args: &str,
                                    extra_params: &Option<Rc<String>>) -> String {
         let type_ok = self.get_type_ok(name);
         let kind = name.to_class_cases();
         let extra = match extra_params {
@@ -927,24 +1187,109 @@ impl CPPExporter {
             kind = kind,
             args = args,
             extra = extra,
             before_context = if args.len() > 0 || extra_params.is_some() {
                 ", "
             } else {
                 ""
             },
-            context = "const Context& context",
+            context = self.get_context_param(name, prefix),
         )
     }
 
+    fn get_context_param_for_sum(&self, sum: &NodeName,
+                                 arm: &NodeName, context: &str) -> String {
+        let sum_name = format!("Sum{}", sum);
+        let arm_name = format!("Interface{}", arm);
+
+        let sum_context = match self.context_map.get(&sum_name) {
+            Some(context) => context.clone(),
+            _ => panic!("no context")
+        };
+        let arm_context = match self.context_map.get(&arm_name) {
+            Some(context) => context.clone(),
+            _ => panic!("no context")
+        };
+
+        if sum_context == arm_context {
+            return context.to_string();
+        }
+
+        assert!(sum_context.is_single());
+        assert!(arm_context.is_valid_double());
+
+        return format!("Context({})", context);
+    }
+
+    fn get_context_param_for_optional(&self, optional: &NodeName,
+                                      body_prefix: &str, body: &NodeName,
+                                      context: &str) -> String {
+        let optional_name = optional.to_string().clone();
+        let body_name = format!("{}{}", body_prefix, body);
+
+        let optional_context = match self.context_map.get(&optional_name) {
+            Some(context) => context.clone(),
+            _ => panic!("no context")
+        };
+        let body_context = match self.context_map.get(&body_name) {
+            Some(context) => context.clone(),
+            _ => panic!("no context")
+        };
+
+        if optional_context == body_context {
+            return context.to_string();
+        }
+
+        assert!(optional_context.is_single());
+        assert!(body_context.is_valid_double());
+
+        return format!("Context({})", context);
+    }
+
+    fn get_context_param_for_list(&self, element: &NodeName,
+                                  context: &str) -> String {
+        let element_name = element.to_string().clone();
+
+        let element_context = match self.context_map.get(&element_name) {
+            Some(context) => context.clone(),
+            _ => panic!("no context")
+        };
+
+        if element_context.is_list() {
+            return context.to_string();
+        }
+
+        assert!(element_context.is_field_and_list());
+
+        return format!("Context({})", context);
+    }
+
+    fn get_context_param_for_field(&self, field: &NodeName,
+                                  context: &str) -> String {
+        let field_name = field.to_string().clone();
+
+        let field_context = match self.context_map.get(&field_name) {
+            Some(context) => context.clone(),
+            _ => panic!("no context")
+        };
+
+        if field_context.is_field() {
+            return context.to_string();
+        }
+
+        assert!(field_context.is_valid_double());
+
+        return format!("Context({})", context);
+    }
+
     fn get_method_call(&self, var_name: &str, name: &NodeName,
                        prefix: &str, args: &str,
                        extra_params: &Option<Rc<String>>,
-                       context_name: &str,
+                       context_name: String,
                        call_kind: MethodCallKind) -> String {
         let type_ok_is_ok = match call_kind {
             MethodCallKind::Decl | MethodCallKind::Var => {
                 self.get_type_ok(name).to_str() == "Ok"
             }
             MethodCallKind::AlwaysDecl | MethodCallKind::AlwaysVar => {
                 false
             }
@@ -1750,17 +2095,17 @@ impl CPPExporter {
     MOZ_TRY(guard.done());
     return result;
 }}
 ",
                 bnf = rendered_bnf,
                 call = self.get_method_call("result", name,
                                             "Sum", INTERFACE_ARGS,
                                             &extra_args,
-                                            "context",
+                                            "context".to_string(),
                                             MethodCallKind::AlwaysDecl)
                     .reindent("    "),
                 first_line = self.get_method_definition_start(name, "", "",
                                                               &extra_params)
             ));
         }
 
         let inner_prefix = "Sum";
@@ -1785,17 +2130,18 @@ impl CPPExporter {
 
             buffer_cases.push_str(&format!("
       case BinASTKind::{variant_name}:
 {call}
 {arm_after}        break;",
                 call = self.get_method_call("result", node,
                                             "Interface", INTERFACE_ARGS,
                                             &extra_args,
-                                            "context",
+                                            self.get_context_param_for_sum(
+                                                name, node, "context"),
                                             MethodCallKind::AlwaysVar)
                     .reindent("        "),
                 variant_name = node.to_cpp_enum_case(),
                 arm_after = rule_for_this_arm.after_arm.reindent("        ")
                     .newline_if_not_empty()));
         }
         buffer.push_str(&format!("
 
@@ -1876,17 +2222,17 @@ impl CPPExporter {
         let rendered = format!("
 
 {first_line}
 {{
     uint32_t length;
     AutoList guard(*tokenizer_);
 
     const auto start = tokenizer_->offset();
-    const Context childContext(Context(ListContext(context.as<FieldContext>().position, BinASTList::{content_kind})));
+    const auto childContext = ListContext(context.position, BinASTList::{content_kind});
     MOZ_TRY(tokenizer_->enterList(length, childContext, guard));{empty_check}
 {init}
 
     for (uint32_t i = 0; i < length; ++i) {{
 {call}
 {append}    }}
 
     MOZ_TRY(guard.done());
@@ -1906,17 +2252,19 @@ impl CPPExporter {
         return raiseEmpty(\"{kind}\");
     }}
 ",
                         kind = kind)
                 },
             call = self.get_method_call("item",
                                         &parser.elements, "", "",
                                         &extra_args,
-                                        "childContext",
+                                        self.get_context_param_for_list(
+                                            &parser.elements,
+                                            "childContext"),
                                         MethodCallKind::Decl)
                 .reindent("        "),
             init = init,
             append = append);
         buffer.push_str(&rendered);
     }
 
     fn generate_implement_option(&self, buffer: &mut String, parser: &OptionParserData) {
@@ -1989,17 +2337,20 @@ impl CPPExporter {
 ",
                     first_line = self.get_method_definition_start(&parser.name, "", "",
                                                                   &extra_params),
                     null = self.syntax.get_null_name().to_cpp_enum_case(),
                     call = self.get_method_call("result",
                                                 &parser.elements,
                                                 "Interface", INTERFACE_ARGS,
                                                 &extra_args,
-                                                "context",
+                                                self.get_context_param_for_optional(
+                                                    &parser.name,
+                                                    "Interface", &parser.elements,
+                                                    "context"),
                                                 MethodCallKind::AlwaysVar)
                         .reindent("        "),
                     before = rules_for_this_node.some_before
                         .map_or_else(|| "".to_string(),
                                      |s| s
                                      .reindent("        ")
                                      .newline_if_not_empty()),
                     after = rules_for_this_node.some_after
@@ -2039,17 +2390,20 @@ impl CPPExporter {
 }}
 
 ",
                             first_line = self.get_method_definition_start(&parser.name, "", "",
                                                                           &extra_params),
                             call = self.get_method_call("result", &parser.elements,
                                                         "Sum", INTERFACE_ARGS,
                                                         &extra_args,
-                                                        "context",
+                                                        self.get_context_param_for_optional(
+                                                            &parser.name,
+                                                            "Sum", &parser.elements,
+                                                            "context"),
                                                         MethodCallKind::AlwaysVar)
                                 .reindent("        "),
                             before = rules_for_this_node.some_before
                                 .map_or_else(|| "".to_string(),
                                              |s| s
                                              .reindent("        ")
                                              .newline_if_not_empty()),
                             after = rules_for_this_node.some_after
@@ -2192,17 +2546,17 @@ impl CPPExporter {
 
 ",
                 first_line = self.get_method_definition_start(name, "", "",
                                                               &extra_params),
                 kind = name.to_cpp_enum_case(),
                 call = self.get_method_call("result", name,
                                             "Interface", INTERFACE_ARGS,
                                             &extra_args,
-                                            "context",
+                                            "context".to_string(),
                                             MethodCallKind::AlwaysDecl)
                     .reindent("    ")
             ));
         }
 
         let inner_prefix = "Interface";
         if !self.refgraph.is_used(Rc::new(format!("{}{}", inner_prefix, name))) {
             return;
@@ -2217,17 +2571,17 @@ impl CPPExporter {
         let fields_type_list = format!("{{ {} }}", interface.contents()
             .fields()
             .iter()
             .map(|field| format!("BinASTField::{}", field.name().to_cpp_enum_case()))
             .format(", "));
 
         let mut fields_implem = String::new();
         for field in interface.contents().fields() {
-            let context = format!("Context(FieldContext(BinASTInterfaceAndField::{kind}__{field}))",
+            let context = format!("FieldContext(BinASTInterfaceAndField::{kind}__{field})",
                 kind = name.to_cpp_enum_case(),
                 field = field.name().to_cpp_enum_case());
 
             let rules_for_this_field = rules_for_this_interface.by_field.get(field.name())
                 .cloned()
                 .unwrap_or_default();
             let needs_block = rules_for_this_field.block_before_field.is_some() || rules_for_this_field.block_after_field.is_some();
 
@@ -2337,17 +2691,19 @@ impl CPPExporter {
                     } else {
                         (None,
                          MethodCallKind::Decl)
                     };
 
                     (decl_var,
                      Some(self.get_method_call(var_name.to_str(),
                                                &name, "", "", &field_extra_args,
-                                               &context,
+                                               self.get_context_param_for_field(
+                                                   name,
+                                                   &context),
                                                call_kind)))
                 }
             };
             let rendered = {
                 if rules_for_this_field.replace.is_some() {
                     for &(condition, rule_name) in &[
                         (rules_for_this_field.before_field.is_some(), "before:"),
                         (rules_for_this_field.after_field.is_some(), "after:"),
@@ -2666,16 +3022,17 @@ fn main() {
         .expect("Could not parse rules");
     assert_eq!(yaml.len(), 1);
 
     let global_rules = GlobalRules::new(&new_syntax, &yaml[0]);
     let mut exporter = CPPExporter::new(new_syntax, global_rules);
 
     exporter.generate_reference_graph();
     exporter.trace(Rc::new(TOPLEVEL_INTERFACE.to_string()));
+    exporter.collect_context();
 
     let write_to = |description, arg, data: &String| {
         let dest_path = matches.value_of(arg)
             .unwrap();
         print!("...exporting {description}: {path} ... ",
             description = description,
             path = dest_path);