Bug 1429613 - Variant matcher callbacks renamed from `match` to `operator()` - r=froydnj
authorGerald Squelart <gsquelart@mozilla.com>
Tue, 02 Apr 2019 11:53:47 +0000
changeset 526415 5753c98c39d1076947bb656a10675ee349c1e6ea
parent 526414 80945e722421a005e54c3c37725c14992b32a23a
child 526416 700ec51653ee51b56cee45ad8bf2797e5ab7aa78
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1429613
milestone68.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 1429613 - Variant matcher callbacks renamed from `match` to `operator()` - r=froydnj Mechanical change from Matcher::match(...) to Matcher::operator()(...). This will now permit the use of generic lambdas, and facilitate the implementation of multi-lambda match. Differential Revision: https://phabricator.services.mozilla.com/D24889
devtools/shared/heapsnapshot/HeapSnapshot.cpp
dom/localstorage/ActorsParent.cpp
dom/media/doctor/DDLogValue.cpp
dom/plugins/ipc/IpdlTuple.h
dom/quota/OriginScope.h
gfx/2d/FilterNodeCapture.cpp
gfx/layers/apz/src/FocusState.cpp
gfx/src/FilterSupport.cpp
ipc/glue/IPCMessageUtils.h
js/public/GCVariant.h
js/src/frontend/EitherParser.h
js/src/vm/Compartment.h
js/src/vm/HelperThreads.cpp
js/src/vm/JSScript.cpp
js/src/vm/JSScript.h
js/src/vm/SavedStacks.cpp
js/src/vm/Stack-inl.h
js/src/vm/UbiNode.cpp
mfbt/Variant.h
mfbt/tests/TestVariant.cpp
modules/libpref/Preferences.cpp
toolkit/components/extensions/WebExtensionPolicy.cpp
xpcom/components/nsComponentManager.cpp
--- a/devtools/shared/heapsnapshot/HeapSnapshot.cpp
+++ b/devtools/shared/heapsnapshot/HeapSnapshot.cpp
@@ -131,28 +131,28 @@ static bool parseMessage(ZeroCopyInputSt
 
 template <typename CharT, typename InternedStringSet>
 struct GetOrInternStringMatcher {
   InternedStringSet& internedStrings;
 
   explicit GetOrInternStringMatcher(InternedStringSet& strings)
       : internedStrings(strings) {}
 
-  const CharT* match(const std::string* str) {
+  const CharT* operator()(const std::string* str) {
     MOZ_ASSERT(str);
     size_t length = str->length() / sizeof(CharT);
     auto tempString = reinterpret_cast<const CharT*>(str->data());
 
     UniqueFreePtr<CharT[]> owned(NS_xstrndup(tempString, length));
     if (!internedStrings.append(std::move(owned))) return nullptr;
 
     return internedStrings.back().get();
   }
 
-  const CharT* match(uint64_t ref) {
+  const CharT* operator()(uint64_t ref) {
     if (MOZ_LIKELY(ref < internedStrings.length())) {
       auto& string = internedStrings[ref];
       MOZ_ASSERT(string);
       return string.get();
     }
 
     return nullptr;
   }
@@ -783,62 +783,66 @@ static bool EstablishBoundaries(JSContex
 
 // A variant covering all the various two-byte strings that we can get from the
 // ubi::Node API.
 class TwoByteString
     : public Variant<JSAtom*, const char16_t*, JS::ubi::EdgeName> {
   using Base = Variant<JSAtom*, const char16_t*, JS::ubi::EdgeName>;
 
   struct AsTwoByteStringMatcher {
-    TwoByteString match(JSAtom* atom) { return TwoByteString(atom); }
+    TwoByteString operator()(JSAtom* atom) { return TwoByteString(atom); }
 
-    TwoByteString match(const char16_t* chars) { return TwoByteString(chars); }
+    TwoByteString operator()(const char16_t* chars) {
+      return TwoByteString(chars);
+    }
   };
 
   struct IsNonNullMatcher {
     template <typename T>
-    bool match(const T& t) {
+    bool operator()(const T& t) {
       return t != nullptr;
     }
   };
 
   struct LengthMatcher {
-    size_t match(JSAtom* atom) {
+    size_t operator()(JSAtom* atom) {
       MOZ_ASSERT(atom);
       JS::ubi::AtomOrTwoByteChars s(atom);
       return s.length();
     }
 
-    size_t match(const char16_t* chars) {
+    size_t operator()(const char16_t* chars) {
       MOZ_ASSERT(chars);
       return NS_strlen(chars);
     }
 
-    size_t match(const JS::ubi::EdgeName& ptr) {
+    size_t operator()(const JS::ubi::EdgeName& ptr) {
       MOZ_ASSERT(ptr);
       return NS_strlen(ptr.get());
     }
   };
 
   struct CopyToBufferMatcher {
     RangedPtr<char16_t> destination;
     size_t maxLength;
 
     CopyToBufferMatcher(RangedPtr<char16_t> destination, size_t maxLength)
         : destination(destination), maxLength(maxLength) {}
 
-    size_t match(JS::ubi::EdgeName& ptr) { return ptr ? match(ptr.get()) : 0; }
+    size_t operator()(JS::ubi::EdgeName& ptr) {
+      return ptr ? operator()(ptr.get()) : 0;
+    }
 
-    size_t match(JSAtom* atom) {
+    size_t operator()(JSAtom* atom) {
       MOZ_ASSERT(atom);
       JS::ubi::AtomOrTwoByteChars s(atom);
       return s.copyToBuffer(destination, maxLength);
     }
 
-    size_t match(const char16_t* chars) {
+    size_t operator()(const char16_t* chars) {
       MOZ_ASSERT(chars);
       JS::ubi::AtomOrTwoByteChars s(chars);
       return s.copyToBuffer(destination, maxLength);
     }
   };
 
  public:
   template <typename T>
@@ -891,46 +895,46 @@ class TwoByteString
 // because each type is generally a different semantic thing in addition to
 // having a slightly different representation. For example, the set of edge
 // names and the set stack frames' source names naturally tend not to overlap
 // very much if at all.
 struct TwoByteString::HashPolicy {
   using Lookup = TwoByteString;
 
   struct HashingMatcher {
-    js::HashNumber match(const JSAtom* atom) {
+    js::HashNumber operator()(const JSAtom* atom) {
       return js::DefaultHasher<const JSAtom*>::hash(atom);
     }
 
-    js::HashNumber match(const char16_t* chars) {
+    js::HashNumber operator()(const char16_t* chars) {
       MOZ_ASSERT(chars);
       auto length = NS_strlen(chars);
       return HashString(chars, length);
     }
 
-    js::HashNumber match(const JS::ubi::EdgeName& ptr) {
+    js::HashNumber operator()(const JS::ubi::EdgeName& ptr) {
       MOZ_ASSERT(ptr);
-      return match(ptr.get());
+      return operator()(ptr.get());
     }
   };
 
   static js::HashNumber hash(const Lookup& l) {
     HashingMatcher hasher;
     return l.match(hasher);
   }
 
   struct EqualityMatcher {
     const TwoByteString& rhs;
     explicit EqualityMatcher(const TwoByteString& rhs) : rhs(rhs) {}
 
-    bool match(const JSAtom* atom) {
+    bool operator()(const JSAtom* atom) {
       return rhs.is<JSAtom*>() && rhs.as<JSAtom*>() == atom;
     }
 
-    bool match(const char16_t* chars) {
+    bool operator()(const char16_t* chars) {
       MOZ_ASSERT(chars);
 
       const char16_t* rhsChars = nullptr;
       if (rhs.is<const char16_t*>())
         rhsChars = rhs.as<const char16_t*>();
       else if (rhs.is<JS::ubi::EdgeName>())
         rhsChars = rhs.as<JS::ubi::EdgeName>().get();
       else
@@ -938,19 +942,19 @@ struct TwoByteString::HashPolicy {
       MOZ_ASSERT(rhsChars);
 
       auto length = NS_strlen(chars);
       if (NS_strlen(rhsChars) != length) return false;
 
       return memcmp(chars, rhsChars, length * sizeof(char16_t)) == 0;
     }
 
-    bool match(const JS::ubi::EdgeName& ptr) {
+    bool operator()(const JS::ubi::EdgeName& ptr) {
       MOZ_ASSERT(ptr);
-      return match(ptr.get());
+      return operator()(ptr.get());
     }
   };
 
   static bool match(const TwoByteString& k, const Lookup& l) {
     EqualityMatcher eq(l);
     return k.match(eq);
   }
 
--- a/dom/localstorage/ActorsParent.cpp
+++ b/dom/localstorage/ActorsParent.cpp
@@ -7228,85 +7228,85 @@ ArchivedOriginScope* ArchivedOriginScope
 
 void ArchivedOriginScope::GetBindingClause(nsACString& aBindingClause) const {
   struct Matcher {
     nsACString* mBindingClause;
 
     explicit Matcher(nsACString* aBindingClause)
         : mBindingClause(aBindingClause) {}
 
-    void match(const Origin& aOrigin) {
+    void operator()(const Origin& aOrigin) {
       *mBindingClause = NS_LITERAL_CSTRING(
           " WHERE originKey = :originKey "
           "AND originAttributes = :originAttributes");
     }
 
-    void match(const Prefix& aPrefix) {
+    void operator()(const Prefix& aPrefix) {
       *mBindingClause = NS_LITERAL_CSTRING(" WHERE originKey = :originKey");
     }
 
-    void match(const Pattern& aPattern) {
+    void operator()(const Pattern& aPattern) {
       *mBindingClause = NS_LITERAL_CSTRING(
           " WHERE originAttributes MATCH :originAttributesPattern");
     }
 
-    void match(const Null& aNull) { *mBindingClause = EmptyCString(); }
+    void operator()(const Null& aNull) { *mBindingClause = EmptyCString(); }
   };
 
   mData.match(Matcher(&aBindingClause));
 }
 
 nsresult ArchivedOriginScope::BindToStatement(
     mozIStorageStatement* aStmt) const {
   MOZ_ASSERT(IsOnIOThread() || IsOnConnectionThread());
   MOZ_ASSERT(aStmt);
 
   struct Matcher {
     mozIStorageStatement* mStmt;
 
     explicit Matcher(mozIStorageStatement* aStmt) : mStmt(aStmt) {}
 
-    nsresult match(const Origin& aOrigin) {
+    nsresult operator()(const Origin& aOrigin) {
       nsresult rv = mStmt->BindUTF8StringByName(NS_LITERAL_CSTRING("originKey"),
                                                 aOrigin.OriginNoSuffix());
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
 
       rv = mStmt->BindUTF8StringByName(NS_LITERAL_CSTRING("originAttributes"),
                                        aOrigin.OriginSuffix());
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
 
       return NS_OK;
     }
 
-    nsresult match(const Prefix& aPrefix) {
+    nsresult operator()(const Prefix& aPrefix) {
       nsresult rv = mStmt->BindUTF8StringByName(NS_LITERAL_CSTRING("originKey"),
                                                 aPrefix.OriginNoSuffix());
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
 
       return NS_OK;
     }
 
-    nsresult match(const Pattern& aPattern) {
+    nsresult operator()(const Pattern& aPattern) {
       nsresult rv = mStmt->BindUTF8StringByName(
           NS_LITERAL_CSTRING("originAttributesPattern"),
           NS_LITERAL_CSTRING("pattern1"));
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
 
       return NS_OK;
     }
 
-    nsresult match(const Null& aNull) { return NS_OK; }
+    nsresult operator()(const Null& aNull) { return NS_OK; }
   };
 
   nsresult rv = mData.match(Matcher(aStmt));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
@@ -7318,95 +7318,95 @@ bool ArchivedOriginScope::HasMatches(
   MOZ_ASSERT(aHashtable);
 
   struct Matcher {
     ArchivedOriginHashtable* mHashtable;
 
     explicit Matcher(ArchivedOriginHashtable* aHashtable)
         : mHashtable(aHashtable) {}
 
-    bool match(const Origin& aOrigin) {
+    bool operator()(const Origin& aOrigin) {
       nsCString hashKey = GetArchivedOriginHashKey(aOrigin.OriginSuffix(),
                                                    aOrigin.OriginNoSuffix());
 
       ArchivedOriginInfo* archivedOriginInfo;
       return mHashtable->Get(hashKey, &archivedOriginInfo);
     }
 
-    bool match(const Prefix& aPrefix) {
+    bool operator()(const Prefix& aPrefix) {
       for (auto iter = mHashtable->ConstIter(); !iter.Done(); iter.Next()) {
         ArchivedOriginInfo* archivedOriginInfo = iter.Data();
 
         if (archivedOriginInfo->mOriginNoSuffix == aPrefix.OriginNoSuffix()) {
           return true;
         }
       }
 
       return false;
     }
 
-    bool match(const Pattern& aPattern) {
+    bool operator()(const Pattern& aPattern) {
       for (auto iter = mHashtable->ConstIter(); !iter.Done(); iter.Next()) {
         ArchivedOriginInfo* archivedOriginInfo = iter.Data();
 
         if (aPattern.GetPattern().Matches(
                 archivedOriginInfo->mOriginAttributes)) {
           return true;
         }
       }
 
       return false;
     }
 
-    bool match(const Null& aNull) { return mHashtable->Count(); }
+    bool operator()(const Null& aNull) { return mHashtable->Count(); }
   };
 
   return mData.match(Matcher(aHashtable));
 }
 
 void ArchivedOriginScope::RemoveMatches(
     ArchivedOriginHashtable* aHashtable) const {
   AssertIsOnIOThread();
   MOZ_ASSERT(aHashtable);
 
   struct Matcher {
     ArchivedOriginHashtable* mHashtable;
 
     explicit Matcher(ArchivedOriginHashtable* aHashtable)
         : mHashtable(aHashtable) {}
 
-    void match(const Origin& aOrigin) {
+    void operator()(const Origin& aOrigin) {
       nsCString hashKey = GetArchivedOriginHashKey(aOrigin.OriginSuffix(),
                                                    aOrigin.OriginNoSuffix());
 
       mHashtable->Remove(hashKey);
     }
 
-    void match(const Prefix& aPrefix) {
+    void operator()(const Prefix& aPrefix) {
       for (auto iter = mHashtable->Iter(); !iter.Done(); iter.Next()) {
         ArchivedOriginInfo* archivedOriginInfo = iter.Data();
 
         if (archivedOriginInfo->mOriginNoSuffix == aPrefix.OriginNoSuffix()) {
           iter.Remove();
         }
       }
     }
 
-    void match(const Pattern& aPattern) {
+    void operator()(const Pattern& aPattern) {
       for (auto iter = mHashtable->Iter(); !iter.Done(); iter.Next()) {
         ArchivedOriginInfo* archivedOriginInfo = iter.Data();
 
         if (aPattern.GetPattern().Matches(
                 archivedOriginInfo->mOriginAttributes)) {
           iter.Remove();
         }
       }
     }
 
-    void match(const Null& aNull) { mHashtable->Clear(); }
+    void operator()(const Null& aNull) { mHashtable->Clear(); }
   };
 
   mData.match(Matcher(aHashtable));
 }
 
 /*******************************************************************************
  * QuotaClient
  ******************************************************************************/
--- a/dom/media/doctor/DDLogValue.cpp
+++ b/dom/media/doctor/DDLogValue.cpp
@@ -8,104 +8,106 @@
 
 #include "mozilla/JSONWriter.h"
 
 namespace mozilla {
 
 struct LogValueMatcher {
   nsCString& mString;
 
-  void match(const DDNoValue&) const {}
-  void match(const DDLogObject& a) const { a.AppendPrintf(mString); }
-  void match(const char* a) const { mString.AppendPrintf(R"("%s")", a); }
-  void match(const nsCString& a) const {
+  void operator()(const DDNoValue&) const {}
+  void operator()(const DDLogObject& a) const { a.AppendPrintf(mString); }
+  void operator()(const char* a) const { mString.AppendPrintf(R"("%s")", a); }
+  void operator()(const nsCString& a) const {
     mString.AppendPrintf(R"(nsCString("%s"))", a.Data());
   }
-  void match(bool a) const { mString.AppendPrintf(a ? "true" : "false"); }
-  void match(int8_t a) const { mString.AppendPrintf("int8_t(%" PRIi8 ")", a); }
-  void match(uint8_t a) const {
+  void operator()(bool a) const { mString.AppendPrintf(a ? "true" : "false"); }
+  void operator()(int8_t a) const {
+    mString.AppendPrintf("int8_t(%" PRIi8 ")", a);
+  }
+  void operator()(uint8_t a) const {
     mString.AppendPrintf("uint8_t(%" PRIu8 ")", a);
   }
-  void match(int16_t a) const {
+  void operator()(int16_t a) const {
     mString.AppendPrintf("int16_t(%" PRIi16 ")", a);
   }
-  void match(uint16_t a) const {
+  void operator()(uint16_t a) const {
     mString.AppendPrintf("uint16_t(%" PRIu16 ")", a);
   }
-  void match(int32_t a) const {
+  void operator()(int32_t a) const {
     mString.AppendPrintf("int32_t(%" PRIi32 ")", a);
   }
-  void match(uint32_t a) const {
+  void operator()(uint32_t a) const {
     mString.AppendPrintf("uint32_t(%" PRIu32 ")", a);
   }
-  void match(int64_t a) const {
+  void operator()(int64_t a) const {
     mString.AppendPrintf("int64_t(%" PRIi64 ")", a);
   }
-  void match(uint64_t a) const {
+  void operator()(uint64_t a) const {
     mString.AppendPrintf("uint64_t(%" PRIu64 ")", a);
   }
-  void match(double a) const { mString.AppendPrintf("double(%f)", a); }
-  void match(const DDRange& a) const {
+  void operator()(double a) const { mString.AppendPrintf("double(%f)", a); }
+  void operator()(const DDRange& a) const {
     mString.AppendPrintf("%" PRIi64 "<=(%" PRIi64 "B)<%" PRIi64 "", a.mOffset,
                          a.mBytes, a.mOffset + a.mBytes);
   }
-  void match(const nsresult& a) const {
+  void operator()(const nsresult& a) const {
     nsCString name;
     GetErrorName(a, name);
     mString.AppendPrintf("nsresult(%s =0x%08" PRIx32 ")", name.get(),
                          static_cast<uint32_t>(a));
   }
-  void match(const MediaResult& a) const {
+  void operator()(const MediaResult& a) const {
     nsCString name;
     GetErrorName(a.Code(), name);
     mString.AppendPrintf("MediaResult(%s =0x%08" PRIx32 ", \"%s\")", name.get(),
                          static_cast<uint32_t>(a.Code()), a.Message().get());
   }
 };
 
 void AppendToString(const DDLogValue& aValue, nsCString& aString) {
   aValue.match(LogValueMatcher{aString});
 }
 
 struct LogValueMatcherJson {
   JSONWriter& mJW;
   const char* mPropertyName;
 
-  void match(const DDNoValue&) const { mJW.NullProperty(mPropertyName); }
-  void match(const DDLogObject& a) const {
+  void operator()(const DDNoValue&) const { mJW.NullProperty(mPropertyName); }
+  void operator()(const DDLogObject& a) const {
     mJW.StringProperty(
         mPropertyName,
         nsPrintfCString(R"("%s[%p]")", a.TypeName(), a.Pointer()).get());
   }
-  void match(const char* a) const { mJW.StringProperty(mPropertyName, a); }
-  void match(const nsCString& a) const {
+  void operator()(const char* a) const { mJW.StringProperty(mPropertyName, a); }
+  void operator()(const nsCString& a) const {
     mJW.StringProperty(mPropertyName, a.Data());
   }
-  void match(bool a) const { mJW.BoolProperty(mPropertyName, a); }
-  void match(int8_t a) const { mJW.IntProperty(mPropertyName, a); }
-  void match(uint8_t a) const { mJW.IntProperty(mPropertyName, a); }
-  void match(int16_t a) const { mJW.IntProperty(mPropertyName, a); }
-  void match(uint16_t a) const { mJW.IntProperty(mPropertyName, a); }
-  void match(int32_t a) const { mJW.IntProperty(mPropertyName, a); }
-  void match(uint32_t a) const { mJW.IntProperty(mPropertyName, a); }
-  void match(int64_t a) const { mJW.IntProperty(mPropertyName, a); }
-  void match(uint64_t a) const { mJW.DoubleProperty(mPropertyName, a); }
-  void match(double a) const { mJW.DoubleProperty(mPropertyName, a); }
-  void match(const DDRange& a) const {
+  void operator()(bool a) const { mJW.BoolProperty(mPropertyName, a); }
+  void operator()(int8_t a) const { mJW.IntProperty(mPropertyName, a); }
+  void operator()(uint8_t a) const { mJW.IntProperty(mPropertyName, a); }
+  void operator()(int16_t a) const { mJW.IntProperty(mPropertyName, a); }
+  void operator()(uint16_t a) const { mJW.IntProperty(mPropertyName, a); }
+  void operator()(int32_t a) const { mJW.IntProperty(mPropertyName, a); }
+  void operator()(uint32_t a) const { mJW.IntProperty(mPropertyName, a); }
+  void operator()(int64_t a) const { mJW.IntProperty(mPropertyName, a); }
+  void operator()(uint64_t a) const { mJW.DoubleProperty(mPropertyName, a); }
+  void operator()(double a) const { mJW.DoubleProperty(mPropertyName, a); }
+  void operator()(const DDRange& a) const {
     mJW.StartArrayProperty(mPropertyName);
     mJW.IntElement(a.mOffset);
     mJW.IntElement(a.mOffset + a.mBytes);
     mJW.EndArray();
   }
-  void match(const nsresult& a) const {
+  void operator()(const nsresult& a) const {
     nsCString name;
     GetErrorName(a, name);
     mJW.StringProperty(mPropertyName, name.get());
   }
-  void match(const MediaResult& a) const {
+  void operator()(const MediaResult& a) const {
     nsCString name;
     GetErrorName(a.Code(), name);
     mJW.StringProperty(mPropertyName,
                        nsPrintfCString(R"lit("MediaResult(%s, %s)")lit",
                                        name.get(), a.Message().get())
                            .get());
   }
 };
--- a/dom/plugins/ipc/IpdlTuple.h
+++ b/dom/plugins/ipc/IpdlTuple.h
@@ -147,17 +147,17 @@ struct ParamTraits<IpdlTuple::IpdlTupleE
     MOZ_RELEASE_ASSERT(!aParam->GetVariant().is<IpdlTuple::InvalidType>());
     return ret;
   }
 
   struct LogMatcher {
     explicit LogMatcher(std::wstring* aLog) : mLog(aLog) {}
 
     template <typename EntryType>
-    void match(const EntryType& aParam) {
+    void operator()(const EntryType& aParam) {
       LogParam(aParam, mLog);
     }
 
    private:
     std::wstring* mLog;
   };
 
   static void Log(const paramType& aParam, std::wstring* aLog) {
--- a/dom/quota/OriginScope.h
+++ b/dom/quota/OriginScope.h
@@ -207,23 +207,29 @@ class OriginScope {
   }
 
   bool Matches(const OriginScope& aOther) const {
     struct Matcher {
       const OriginScope& mThis;
 
       explicit Matcher(const OriginScope& aThis) : mThis(aThis) {}
 
-      bool match(const Origin& aOther) { return mThis.MatchesOrigin(aOther); }
-
-      bool match(const Prefix& aOther) { return mThis.MatchesPrefix(aOther); }
+      bool operator()(const Origin& aOther) {
+        return mThis.MatchesOrigin(aOther);
+      }
 
-      bool match(const Pattern& aOther) { return mThis.MatchesPattern(aOther); }
+      bool operator()(const Prefix& aOther) {
+        return mThis.MatchesPrefix(aOther);
+      }
 
-      bool match(const Null& aOther) { return true; }
+      bool operator()(const Pattern& aOther) {
+        return mThis.MatchesPattern(aOther);
+      }
+
+      bool operator()(const Null& aOther) { return true; }
     };
 
     return aOther.mData.match(Matcher(*this));
   }
 
   OriginScope Clone() { return OriginScope(mData); }
 
  private:
@@ -240,89 +246,89 @@ class OriginScope {
   explicit OriginScope(const DataType& aOther) : mData(aOther) {}
 
   bool MatchesOrigin(const Origin& aOther) const {
     struct OriginMatcher {
       const Origin& mOther;
 
       explicit OriginMatcher(const Origin& aOther) : mOther(aOther) {}
 
-      bool match(const Origin& aThis) {
+      bool operator()(const Origin& aThis) {
         return aThis.GetOrigin().Equals(mOther.GetOrigin());
       }
 
-      bool match(const Prefix& aThis) {
+      bool operator()(const Prefix& aThis) {
         return aThis.GetOriginNoSuffix().Equals(mOther.GetOriginNoSuffix());
       }
 
-      bool match(const Pattern& aThis) {
+      bool operator()(const Pattern& aThis) {
         return aThis.GetPattern().Matches(mOther.GetAttributes());
       }
 
-      bool match(const Null& aThis) {
+      bool operator()(const Null& aThis) {
         // Null covers everything.
         return true;
       }
     };
 
     return mData.match(OriginMatcher(aOther));
   }
 
   bool MatchesPrefix(const Prefix& aOther) const {
     struct PrefixMatcher {
       const Prefix& mOther;
 
       explicit PrefixMatcher(const Prefix& aOther) : mOther(aOther) {}
 
-      bool match(const Origin& aThis) {
+      bool operator()(const Origin& aThis) {
         return aThis.GetOriginNoSuffix().Equals(mOther.GetOriginNoSuffix());
       }
 
-      bool match(const Prefix& aThis) {
+      bool operator()(const Prefix& aThis) {
         return aThis.GetOriginNoSuffix().Equals(mOther.GetOriginNoSuffix());
       }
 
-      bool match(const Pattern& aThis) {
+      bool operator()(const Pattern& aThis) {
         // The match will be always true here because any origin attributes
         // pattern overlaps any origin prefix (an origin prefix targets all
         // origin attributes).
         return true;
       }
 
-      bool match(const Null& aThis) {
+      bool operator()(const Null& aThis) {
         // Null covers everything.
         return true;
       }
     };
 
     return mData.match(PrefixMatcher(aOther));
   }
 
   bool MatchesPattern(const Pattern& aOther) const {
     struct PatternMatcher {
       const Pattern& mOther;
 
       explicit PatternMatcher(const Pattern& aOther) : mOther(aOther) {}
 
-      bool match(const Origin& aThis) {
+      bool operator()(const Origin& aThis) {
         return mOther.GetPattern().Matches(aThis.GetAttributes());
       }
 
-      bool match(const Prefix& aThis) {
+      bool operator()(const Prefix& aThis) {
         // The match will be always true here because any origin attributes
         // pattern overlaps any origin prefix (an origin prefix targets all
         // origin attributes).
         return true;
       }
 
-      bool match(const Pattern& aThis) {
+      bool operator()(const Pattern& aThis) {
         return aThis.GetPattern().Overlaps(mOther.GetPattern());
       }
 
-      bool match(const Null& aThis) {
+      bool operator()(const Null& aThis) {
         // Null covers everything.
         return true;
       }
     };
 
     PatternMatcher patternMatcher(aOther);
     return mData.match(PatternMatcher(aOther));
   }
--- a/gfx/2d/FilterNodeCapture.cpp
+++ b/gfx/2d/FilterNodeCapture.cpp
@@ -8,41 +8,42 @@
 
 namespace mozilla {
 namespace gfx {
 
 struct Setter {
   Setter(FilterNode* aNode, DrawTarget* aDT, bool aInputsChanged)
       : mNode{aNode}, mIndex{0}, mDT{aDT}, mInputsChanged{aInputsChanged} {}
   template <typename T>
-  void match(T& aValue) {
+  void operator()(T& aValue) {
     mNode->SetAttribute(mIndex, aValue);
   }
 
   FilterNode* mNode;
   uint32_t mIndex;
   DrawTarget* mDT;
   bool mInputsChanged;
 };
 
 template <>
-void Setter::match<std::vector<Float>>(std::vector<Float>& aValue) {
+void Setter::operator()<std::vector<Float>>(std::vector<Float>& aValue) {
   mNode->SetAttribute(mIndex, aValue.data(), aValue.size());
 }
 
 template <>
-void Setter::match<RefPtr<SourceSurface>>(RefPtr<SourceSurface>& aSurface) {
+void Setter::operator()<RefPtr<SourceSurface>>(
+    RefPtr<SourceSurface>& aSurface) {
   if (!mInputsChanged) {
     return;
   }
   mNode->SetInput(mIndex, aSurface);
 }
 
 template <>
-void Setter::match<RefPtr<FilterNode>>(RefPtr<FilterNode>& aNode) {
+void Setter::operator()<RefPtr<FilterNode>>(RefPtr<FilterNode>& aNode) {
   RefPtr<FilterNode> node = aNode;
   if (node->GetBackendType() == FilterBackend::FILTER_BACKEND_CAPTURE) {
     FilterNodeCapture* captureNode =
         static_cast<FilterNodeCapture*>(node.get());
     node = captureNode->Validate(mDT);
   }
   if (!mInputsChanged) {
     return;
--- a/gfx/layers/apz/src/FocusState.cpp
+++ b/gfx/layers/apz/src/FocusState.cpp
@@ -97,17 +97,17 @@ void FocusState::Update(LayersId aRootLa
     // Match on the data stored in mData
     // The match functions return true or false depending on whether the
     // enclosing method, FocusState::Update, should return or continue to the
     // next iteration of the while loop, respectively.
     struct FocusTargetDataMatcher {
       FocusState& mFocusState;
       const uint64_t mSequenceNumber;
 
-      bool match(const FocusTarget::NoFocusTarget& aNoFocusTarget) {
+      bool operator()(const FocusTarget::NoFocusTarget& aNoFocusTarget) {
         FS_LOG("Setting target to nil (reached a nil target) with seq=%" PRIu64
                "\n",
                mSequenceNumber);
 
         // Mark what sequence number this target has for debugging purposes so
         // we can always accurately report on whether we are stale or not
         mFocusState.mLastContentProcessedEvent = mSequenceNumber;
 
@@ -118,17 +118,17 @@ void FocusState::Update(LayersId aRootLa
             mFocusState.mLastContentProcessedEvent >
                 mFocusState.mLastAPZProcessedEvent) {
           mFocusState.mLastAPZProcessedEvent =
               mFocusState.mLastContentProcessedEvent;
         }
         return true;
       }
 
-      bool match(const LayersId& aRefLayerId) {
+      bool operator()(const LayersId& aRefLayerId) {
         // Guard against infinite loops
         MOZ_ASSERT(mFocusState.mFocusLayersId != aRefLayerId);
         if (mFocusState.mFocusLayersId == aRefLayerId) {
           FS_LOG(
               "Setting target to nil (bailing out of infinite loop, lt=%" PRIu64
               ")\n",
               mFocusState.mFocusLayersId);
           return true;
@@ -136,17 +136,17 @@ void FocusState::Update(LayersId aRootLa
 
         FS_LOG("Looking for target in lt=%" PRIu64 "\n", aRefLayerId);
 
         // The focus target is in a child layer tree
         mFocusState.mFocusLayersId = aRefLayerId;
         return false;
       }
 
-      bool match(const FocusTarget::ScrollTargets& aScrollTargets) {
+      bool operator()(const FocusTarget::ScrollTargets& aScrollTargets) {
         FS_LOG("Setting target to h=%" PRIu64 ", v=%" PRIu64
                ", and seq=%" PRIu64 "\n",
                aScrollTargets.mHorizontal, aScrollTargets.mVertical,
                mSequenceNumber);
 
         // This is the global focus target
         mFocusState.mFocusHorizontalTarget = aScrollTargets.mHorizontal;
         mFocusState.mFocusVerticalTarget = aScrollTargets.mVertical;
--- a/gfx/src/FilterSupport.cpp
+++ b/gfx/src/FilterSupport.cpp
@@ -663,22 +663,22 @@ static already_AddRefed<FilterNode> Filt
           mInputImages(aInputImages) {}
 
     const FilterPrimitiveDescription& mDescription;
     DrawTarget* mDT;
     nsTArray<RefPtr<FilterNode>>& mSources;
     nsTArray<IntRect>& mSourceRegions;
     nsTArray<RefPtr<SourceSurface>>& mInputImages;
 
-    already_AddRefed<FilterNode> match(
+    already_AddRefed<FilterNode> operator()(
         const EmptyAttributes& aEmptyAttributes) {
       return nullptr;
     }
 
-    already_AddRefed<FilterNode> match(const BlendAttributes& aBlend) {
+    already_AddRefed<FilterNode> operator()(const BlendAttributes& aBlend) {
       uint32_t mode = aBlend.mBlendMode;
       RefPtr<FilterNode> filter;
       if (mode == SVG_FEBLEND_MODE_UNKNOWN) {
         return nullptr;
       }
       if (mode == SVG_FEBLEND_MODE_NORMAL) {
         filter = mDT->CreateFilter(FilterType::COMPOSITE);
         if (!filter) {
@@ -713,17 +713,17 @@ static already_AddRefed<FilterNode> Filt
         // The correct input order for both software and D2D filters is flipped
         // from our source order, so flip here.
         filter->SetInput(IN_BLEND_IN, mSources[1]);
         filter->SetInput(IN_BLEND_IN2, mSources[0]);
       }
       return filter.forget();
     }
 
-    already_AddRefed<FilterNode> match(
+    already_AddRefed<FilterNode> operator()(
         const ColorMatrixAttributes& aMatrixAttributes) {
       float colorMatrix[20];
       if (!ComputeColorMatrix(aMatrixAttributes, colorMatrix)) {
         RefPtr<FilterNode> filter(mSources[0]);
         return filter.forget();
       }
 
       Matrix5x4 matrix(
@@ -739,17 +739,17 @@ static already_AddRefed<FilterNode> Filt
       }
       filter->SetAttribute(ATT_COLOR_MATRIX_MATRIX, matrix);
       filter->SetAttribute(ATT_COLOR_MATRIX_ALPHA_MODE,
                            (uint32_t)ALPHA_MODE_STRAIGHT);
       filter->SetInput(IN_COLOR_MATRIX_IN, mSources[0]);
       return filter.forget();
     }
 
-    already_AddRefed<FilterNode> match(
+    already_AddRefed<FilterNode> operator()(
         const MorphologyAttributes& aMorphology) {
       Size radii = aMorphology.mRadii;
       int32_t rx = radii.width;
       int32_t ry = radii.height;
       if (rx < 0 || ry < 0) {
         // XXX SVGContentUtils::ReportToConsole()
         return nullptr;
       }
@@ -770,37 +770,37 @@ static already_AddRefed<FilterNode> Filt
         return nullptr;
       }
       filter->SetAttribute(ATT_MORPHOLOGY_RADII, IntSize(rx, ry));
       filter->SetAttribute(ATT_MORPHOLOGY_OPERATOR, (uint32_t)op);
       filter->SetInput(IN_MORPHOLOGY_IN, mSources[0]);
       return filter.forget();
     }
 
-    already_AddRefed<FilterNode> match(const FloodAttributes& aFlood) {
+    already_AddRefed<FilterNode> operator()(const FloodAttributes& aFlood) {
       Color color = aFlood.mColor;
       RefPtr<FilterNode> filter = mDT->CreateFilter(FilterType::FLOOD);
       if (!filter) {
         return nullptr;
       }
       filter->SetAttribute(ATT_FLOOD_COLOR, color);
       return filter.forget();
     }
 
-    already_AddRefed<FilterNode> match(const TileAttributes& aTile) {
+    already_AddRefed<FilterNode> operator()(const TileAttributes& aTile) {
       RefPtr<FilterNode> filter = mDT->CreateFilter(FilterType::TILE);
       if (!filter) {
         return nullptr;
       }
       filter->SetAttribute(ATT_TILE_SOURCE_RECT, mSourceRegions[0]);
       filter->SetInput(IN_TILE_IN, mSources[0]);
       return filter.forget();
     }
 
-    already_AddRefed<FilterNode> match(
+    already_AddRefed<FilterNode> operator()(
         const ComponentTransferAttributes& aComponentTransfer) {
       RefPtr<FilterNode> filters[4];  // one for each FILTER_*_TRANSFER type
       bool useRgb = aComponentTransfer.mTypes[kChannelG] ==
                         SVG_FECOMPONENTTRANSFER_TYPE_UNKNOWN &&
                     aComponentTransfer.mTypes[kChannelB] ==
                         SVG_FECOMPONENTTRANSFER_TYPE_UNKNOWN;
 
       for (int32_t i = 0; i < 4; i++) {
@@ -817,27 +817,27 @@ static already_AddRefed<FilterNode> Filt
           filters[i]->SetInput(0, lastFilter);
           lastFilter = filters[i];
         }
       }
 
       return lastFilter.forget();
     }
 
-    already_AddRefed<FilterNode> match(const OpacityAttributes& aOpacity) {
+    already_AddRefed<FilterNode> operator()(const OpacityAttributes& aOpacity) {
       RefPtr<FilterNode> filter = mDT->CreateFilter(FilterType::OPACITY);
       if (!filter) {
         return nullptr;
       }
       filter->SetAttribute(ATT_OPACITY_VALUE, aOpacity.mOpacity);
       filter->SetInput(IN_OPACITY_IN, mSources[0]);
       return filter.forget();
     }
 
-    already_AddRefed<FilterNode> match(
+    already_AddRefed<FilterNode> operator()(
         const ConvolveMatrixAttributes& aConvolveMatrix) {
       RefPtr<FilterNode> filter =
           mDT->CreateFilter(FilterType::CONVOLVE_MATRIX);
       if (!filter) {
         return nullptr;
       }
       filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_SIZE,
                            aConvolveMatrix.mKernelSize);
@@ -861,21 +861,21 @@ static already_AddRefed<FilterNode> Filt
       filter->SetAttribute(ATT_CONVOLVE_MATRIX_KERNEL_UNIT_LENGTH,
                            aConvolveMatrix.mKernelUnitLength);
       filter->SetAttribute(ATT_CONVOLVE_MATRIX_PRESERVE_ALPHA,
                            aConvolveMatrix.mPreserveAlpha);
       filter->SetInput(IN_CONVOLVE_MATRIX_IN, mSources[0]);
       return filter.forget();
     }
 
-    already_AddRefed<FilterNode> match(const OffsetAttributes& aOffset) {
+    already_AddRefed<FilterNode> operator()(const OffsetAttributes& aOffset) {
       return FilterWrappers::Offset(mDT, mSources[0], aOffset.mValue);
     }
 
-    already_AddRefed<FilterNode> match(
+    already_AddRefed<FilterNode> operator()(
         const DisplacementMapAttributes& aDisplacementMap) {
       RefPtr<FilterNode> filter =
           mDT->CreateFilter(FilterType::DISPLACEMENT_MAP);
       if (!filter) {
         return nullptr;
       }
       filter->SetAttribute(ATT_DISPLACEMENT_MAP_SCALE, aDisplacementMap.mScale);
       static const uint8_t channel[SVG_CHANNEL_A + 1] = {
@@ -889,17 +889,17 @@ static already_AddRefed<FilterNode> Filt
                            (uint32_t)channel[aDisplacementMap.mXChannel]);
       filter->SetAttribute(ATT_DISPLACEMENT_MAP_Y_CHANNEL,
                            (uint32_t)channel[aDisplacementMap.mYChannel]);
       filter->SetInput(IN_DISPLACEMENT_MAP_IN, mSources[0]);
       filter->SetInput(IN_DISPLACEMENT_MAP_IN2, mSources[1]);
       return filter.forget();
     }
 
-    already_AddRefed<FilterNode> match(
+    already_AddRefed<FilterNode> operator()(
         const TurbulenceAttributes& aTurbulence) {
       RefPtr<FilterNode> filter = mDT->CreateFilter(FilterType::TURBULENCE);
       if (!filter) {
         return nullptr;
       }
       filter->SetAttribute(ATT_TURBULENCE_BASE_FREQUENCY,
                            aTurbulence.mBaseFrequency);
       filter->SetAttribute(ATT_TURBULENCE_NUM_OCTAVES, aTurbulence.mOctaves);
@@ -913,17 +913,18 @@ static already_AddRefed<FilterNode> Filt
       filter->SetAttribute(ATT_TURBULENCE_TYPE,
                            (uint32_t)type[aTurbulence.mType]);
       filter->SetAttribute(
           ATT_TURBULENCE_RECT,
           mDescription.PrimitiveSubregion() - aTurbulence.mOffset);
       return FilterWrappers::Offset(mDT, filter, aTurbulence.mOffset);
     }
 
-    already_AddRefed<FilterNode> match(const CompositeAttributes& aComposite) {
+    already_AddRefed<FilterNode> operator()(
+        const CompositeAttributes& aComposite) {
       RefPtr<FilterNode> filter;
       uint32_t op = aComposite.mOperator;
       if (op == SVG_FECOMPOSITE_OPERATOR_ARITHMETIC) {
         const nsTArray<float>& coefficients = aComposite.mCoefficients;
         static const float allZero[4] = {0, 0, 0, 0};
         filter = mDT->CreateFilter(FilterType::ARITHMETIC_COMBINE);
         // All-zero coefficients sometimes occur in junk filters.
         if (!filter || (coefficients.Length() == ArrayLength(allZero) &&
@@ -950,17 +951,17 @@ static already_AddRefed<FilterNode> Filt
         };
         filter->SetAttribute(ATT_COMPOSITE_OPERATOR, (uint32_t)operators[op]);
         filter->SetInput(IN_COMPOSITE_IN_START, mSources[1]);
         filter->SetInput(IN_COMPOSITE_IN_START + 1, mSources[0]);
       }
       return filter.forget();
     }
 
-    already_AddRefed<FilterNode> match(const MergeAttributes& aMerge) {
+    already_AddRefed<FilterNode> operator()(const MergeAttributes& aMerge) {
       if (mSources.Length() == 0) {
         return nullptr;
       }
       if (mSources.Length() == 1) {
         RefPtr<FilterNode> filter(mSources[0]);
         return filter.forget();
       }
       RefPtr<FilterNode> filter = mDT->CreateFilter(FilterType::COMPOSITE);
@@ -970,23 +971,23 @@ static already_AddRefed<FilterNode> Filt
       filter->SetAttribute(ATT_COMPOSITE_OPERATOR,
                            (uint32_t)COMPOSITE_OPERATOR_OVER);
       for (size_t i = 0; i < mSources.Length(); i++) {
         filter->SetInput(IN_COMPOSITE_IN_START + i, mSources[i]);
       }
       return filter.forget();
     }
 
-    already_AddRefed<FilterNode> match(
+    already_AddRefed<FilterNode> operator()(
         const GaussianBlurAttributes& aGaussianBlur) {
       return FilterWrappers::GaussianBlur(mDT, mSources[0],
                                           aGaussianBlur.mStdDeviation);
     }
 
-    already_AddRefed<FilterNode> match(
+    already_AddRefed<FilterNode> operator()(
         const DropShadowAttributes& aDropShadow) {
       RefPtr<FilterNode> alpha = FilterWrappers::ToAlpha(mDT, mSources[0]);
       RefPtr<FilterNode> blur =
           FilterWrappers::GaussianBlur(mDT, alpha, aDropShadow.mStdDeviation);
       RefPtr<FilterNode> offsetBlur =
           FilterWrappers::Offset(mDT, blur, aDropShadow.mOffset);
       RefPtr<FilterNode> flood = mDT->CreateFilter(FilterType::FLOOD);
       if (!flood) {
@@ -1015,23 +1016,23 @@ static already_AddRefed<FilterNode> Filt
       }
       filter->SetAttribute(ATT_COMPOSITE_OPERATOR,
                            (uint32_t)COMPOSITE_OPERATOR_OVER);
       filter->SetInput(IN_COMPOSITE_IN_START, composite);
       filter->SetInput(IN_COMPOSITE_IN_START + 1, mSources[0]);
       return filter.forget();
     }
 
-    already_AddRefed<FilterNode> match(
+    already_AddRefed<FilterNode> operator()(
         const SpecularLightingAttributes& aLighting) {
-      return match(
+      return operator()(
           *(static_cast<const DiffuseLightingAttributes*>(&aLighting)));
     }
 
-    already_AddRefed<FilterNode> match(
+    already_AddRefed<FilterNode> operator()(
         const DiffuseLightingAttributes& aLighting) {
       bool isSpecular =
           mDescription.Attributes().is<SpecularLightingAttributes>();
 
       if (aLighting.mLightType == LightType::None) {
         return nullptr;
       }
 
@@ -1112,17 +1113,17 @@ static already_AddRefed<FilterNode> Filt
         }
       }
 
       filter->SetInput(IN_LIGHTING_IN, mSources[0]);
 
       return filter.forget();
     }
 
-    already_AddRefed<FilterNode> match(const ImageAttributes& aImage) {
+    already_AddRefed<FilterNode> operator()(const ImageAttributes& aImage) {
       const Matrix& TM = aImage.mTransform;
       if (!TM.Determinant()) {
         return nullptr;
       }
 
       // Pull the image from the additional image list using the index that's
       // stored in the primitive description.
       RefPtr<SourceSurface> inputImage = mInputImages[aImage.mInputIndex];
@@ -1132,17 +1133,17 @@ static already_AddRefed<FilterNode> Filt
         return nullptr;
       }
       transform->SetInput(IN_TRANSFORM_IN, inputImage);
       transform->SetAttribute(ATT_TRANSFORM_MATRIX, TM);
       transform->SetAttribute(ATT_TRANSFORM_FILTER, aImage.mFilter);
       return transform.forget();
     }
 
-    already_AddRefed<FilterNode> match(const ToAlphaAttributes& aToAlpha) {
+    already_AddRefed<FilterNode> operator()(const ToAlphaAttributes& aToAlpha) {
       return FilterWrappers::ToAlpha(mDT, mSources[0]);
     }
   };
 
   return aDescription.Attributes().match(PrimitiveAttributesMatcher(
       aDescription, aDT, aSources, aSourceRegions, aInputImages));
 }
 
@@ -1362,123 +1363,128 @@ static nsIntRegion ResultChangeRegionFor
     PrimitiveAttributesMatcher(const FilterPrimitiveDescription& aDescription,
                                const nsTArray<nsIntRegion>& aInputChangeRegions)
         : mDescription(aDescription),
           mInputChangeRegions(aInputChangeRegions) {}
 
     const FilterPrimitiveDescription& mDescription;
     const nsTArray<nsIntRegion>& mInputChangeRegions;
 
-    nsIntRegion match(const EmptyAttributes& aEmptyAttributes) {
+    nsIntRegion operator()(const EmptyAttributes& aEmptyAttributes) {
       return nsIntRegion();
     }
 
-    nsIntRegion match(const BlendAttributes& aBlend) {
+    nsIntRegion operator()(const BlendAttributes& aBlend) {
       return UnionOfRegions(mInputChangeRegions);
     }
 
-    nsIntRegion match(const ColorMatrixAttributes& aColorMatrix) {
+    nsIntRegion operator()(const ColorMatrixAttributes& aColorMatrix) {
       return mInputChangeRegions[0];
     }
 
-    nsIntRegion match(const MorphologyAttributes& aMorphology) {
+    nsIntRegion operator()(const MorphologyAttributes& aMorphology) {
       Size radii = aMorphology.mRadii;
       int32_t rx = clamped(int32_t(ceil(radii.width)), 0, kMorphologyMaxRadius);
       int32_t ry =
           clamped(int32_t(ceil(radii.height)), 0, kMorphologyMaxRadius);
       return mInputChangeRegions[0].Inflated(nsIntMargin(ry, rx, ry, rx));
     }
 
-    nsIntRegion match(const FloodAttributes& aFlood) { return nsIntRegion(); }
+    nsIntRegion operator()(const FloodAttributes& aFlood) {
+      return nsIntRegion();
+    }
 
-    nsIntRegion match(const TileAttributes& aTile) {
+    nsIntRegion operator()(const TileAttributes& aTile) {
       return mDescription.PrimitiveSubregion();
     }
 
-    nsIntRegion match(const ComponentTransferAttributes& aComponentTransfer) {
+    nsIntRegion operator()(
+        const ComponentTransferAttributes& aComponentTransfer) {
       return mInputChangeRegions[0];
     }
 
-    nsIntRegion match(const OpacityAttributes& aOpacity) {
+    nsIntRegion operator()(const OpacityAttributes& aOpacity) {
       return UnionOfRegions(mInputChangeRegions);
     }
 
-    nsIntRegion match(const ConvolveMatrixAttributes& aConvolveMatrix) {
+    nsIntRegion operator()(const ConvolveMatrixAttributes& aConvolveMatrix) {
       if (aConvolveMatrix.mEdgeMode != EDGE_MODE_NONE) {
         return mDescription.PrimitiveSubregion();
       }
       Size kernelUnitLength = aConvolveMatrix.mKernelUnitLength;
       IntSize kernelSize = aConvolveMatrix.mKernelSize;
       IntPoint target = aConvolveMatrix.mTarget;
       nsIntMargin m(
           ceil(kernelUnitLength.width * (target.x)),
           ceil(kernelUnitLength.height * (target.y)),
           ceil(kernelUnitLength.width * (kernelSize.width - target.x - 1)),
           ceil(kernelUnitLength.height * (kernelSize.height - target.y - 1)));
       return mInputChangeRegions[0].Inflated(m);
     }
 
-    nsIntRegion match(const OffsetAttributes& aOffset) {
+    nsIntRegion operator()(const OffsetAttributes& aOffset) {
       IntPoint offset = aOffset.mValue;
       return mInputChangeRegions[0].MovedBy(offset.x, offset.y);
     }
 
-    nsIntRegion match(const DisplacementMapAttributes& aDisplacementMap) {
+    nsIntRegion operator()(const DisplacementMapAttributes& aDisplacementMap) {
       int32_t scale = ceil(std::abs(aDisplacementMap.mScale));
       return mInputChangeRegions[0].Inflated(
           nsIntMargin(scale, scale, scale, scale));
     }
 
-    nsIntRegion match(const TurbulenceAttributes& aTurbulence) {
+    nsIntRegion operator()(const TurbulenceAttributes& aTurbulence) {
       return nsIntRegion();
     }
 
-    nsIntRegion match(const CompositeAttributes& aComposite) {
+    nsIntRegion operator()(const CompositeAttributes& aComposite) {
       return UnionOfRegions(mInputChangeRegions);
     }
 
-    nsIntRegion match(const MergeAttributes& aMerge) {
+    nsIntRegion operator()(const MergeAttributes& aMerge) {
       return UnionOfRegions(mInputChangeRegions);
     }
 
-    nsIntRegion match(const GaussianBlurAttributes& aGaussianBlur) {
+    nsIntRegion operator()(const GaussianBlurAttributes& aGaussianBlur) {
       const Size& stdDeviation = aGaussianBlur.mStdDeviation;
       int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
       int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
       return mInputChangeRegions[0].Inflated(nsIntMargin(dy, dx, dy, dx));
     }
 
-    nsIntRegion match(const DropShadowAttributes& aDropShadow) {
+    nsIntRegion operator()(const DropShadowAttributes& aDropShadow) {
       IntPoint offset = aDropShadow.mOffset;
       nsIntRegion offsetRegion =
           mInputChangeRegions[0].MovedBy(offset.x, offset.y);
       Size stdDeviation = aDropShadow.mStdDeviation;
       int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
       int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
       nsIntRegion blurRegion =
           offsetRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
       blurRegion.Or(blurRegion, mInputChangeRegions[0]);
       return blurRegion;
     }
 
-    nsIntRegion match(const SpecularLightingAttributes& aLighting) {
-      return match(
+    nsIntRegion operator()(const SpecularLightingAttributes& aLighting) {
+      return operator()(
           *(static_cast<const DiffuseLightingAttributes*>(&aLighting)));
     }
 
-    nsIntRegion match(const DiffuseLightingAttributes& aLighting) {
+    nsIntRegion operator()(const DiffuseLightingAttributes& aLighting) {
       Size kernelUnitLength = aLighting.mKernelUnitLength;
       int32_t dx = ceil(kernelUnitLength.width);
       int32_t dy = ceil(kernelUnitLength.height);
       return mInputChangeRegions[0].Inflated(nsIntMargin(dy, dx, dy, dx));
     }
 
-    nsIntRegion match(const ImageAttributes& aImage) { return nsIntRegion(); }
+    nsIntRegion operator()(const ImageAttributes& aImage) {
+      return nsIntRegion();
+    }
 
-    nsIntRegion match(const ToAlphaAttributes& aToAlpha) {
+    nsIntRegion operator()(const ToAlphaAttributes& aToAlpha) {
       return mInputChangeRegions[0];
     }
   };
 
   return aDescription.Attributes().match(
       PrimitiveAttributesMatcher(aDescription, aInputChangeRegions));
 }
 
@@ -1555,86 +1561,87 @@ nsIntRegion FilterSupport::PostFilterExt
   struct PrimitiveAttributesMatcher {
     PrimitiveAttributesMatcher(const FilterPrimitiveDescription& aDescription,
                                const nsTArray<nsIntRegion>& aInputExtents)
         : mDescription(aDescription), mInputExtents(aInputExtents) {}
 
     const FilterPrimitiveDescription& mDescription;
     const nsTArray<nsIntRegion>& mInputExtents;
 
-    nsIntRegion match(const EmptyAttributes& aEmptyAttributes) {
+    nsIntRegion operator()(const EmptyAttributes& aEmptyAttributes) {
       return IntRect();
     }
 
-    nsIntRegion match(const BlendAttributes& aBlend) {
+    nsIntRegion operator()(const BlendAttributes& aBlend) {
       return ResultChangeRegionForPrimitive(mDescription, mInputExtents);
     }
 
-    nsIntRegion match(const ColorMatrixAttributes& aColorMatrix) {
+    nsIntRegion operator()(const ColorMatrixAttributes& aColorMatrix) {
       if (aColorMatrix.mType == (uint32_t)SVG_FECOLORMATRIX_TYPE_MATRIX) {
         const nsTArray<float>& values = aColorMatrix.mValues;
         if (values.Length() == 20 && values[19] > 0.0f) {
           return mDescription.PrimitiveSubregion();
         }
       }
       return mInputExtents[0];
     }
 
-    nsIntRegion match(const MorphologyAttributes& aMorphology) {
+    nsIntRegion operator()(const MorphologyAttributes& aMorphology) {
       uint32_t op = aMorphology.mOperator;
       if (op == SVG_OPERATOR_ERODE) {
         return mInputExtents[0];
       }
       Size radii = aMorphology.mRadii;
       int32_t rx = clamped(int32_t(ceil(radii.width)), 0, kMorphologyMaxRadius);
       int32_t ry =
           clamped(int32_t(ceil(radii.height)), 0, kMorphologyMaxRadius);
       return mInputExtents[0].Inflated(nsIntMargin(ry, rx, ry, rx));
     }
 
-    nsIntRegion match(const FloodAttributes& aFlood) {
+    nsIntRegion operator()(const FloodAttributes& aFlood) {
       if (aFlood.mColor.a == 0.0f) {
         return IntRect();
       }
       return mDescription.PrimitiveSubregion();
     }
 
-    nsIntRegion match(const TileAttributes& aTile) {
+    nsIntRegion operator()(const TileAttributes& aTile) {
       return ResultChangeRegionForPrimitive(mDescription, mInputExtents);
     }
 
-    nsIntRegion match(const ComponentTransferAttributes& aComponentTransfer) {
+    nsIntRegion operator()(
+        const ComponentTransferAttributes& aComponentTransfer) {
       if (ResultOfZeroUnderTransferFunction(aComponentTransfer, kChannelA) >
           0.0f) {
         return mDescription.PrimitiveSubregion();
       }
       return mInputExtents[0];
     }
 
-    nsIntRegion match(const OpacityAttributes& aOpacity) {
+    nsIntRegion operator()(const OpacityAttributes& aOpacity) {
       return ResultChangeRegionForPrimitive(mDescription, mInputExtents);
     }
 
-    nsIntRegion match(const ConvolveMatrixAttributes& aConvolveMatrix) {
+    nsIntRegion operator()(const ConvolveMatrixAttributes& aConvolveMatrix) {
       return ResultChangeRegionForPrimitive(mDescription, mInputExtents);
     }
 
-    nsIntRegion match(const OffsetAttributes& aOffset) {
+    nsIntRegion operator()(const OffsetAttributes& aOffset) {
       return ResultChangeRegionForPrimitive(mDescription, mInputExtents);
     }
 
-    nsIntRegion match(const DisplacementMapAttributes& aDisplacementMap) {
+    nsIntRegion operator()(const DisplacementMapAttributes& aDisplacementMap) {
       return ResultChangeRegionForPrimitive(mDescription, mInputExtents);
     }
 
-    nsIntRegion match(const TurbulenceAttributes& aTurbulence) {
+    nsIntRegion operator()(const TurbulenceAttributes& aTurbulence) {
       return mDescription.PrimitiveSubregion();
     }
 
-    nsIntRegion match(const CompositeAttributes& aComposite) {
+    nsIntRegion operator()(const CompositeAttributes& aComposite) {
       uint32_t op = aComposite.mOperator;
       if (op == SVG_FECOMPOSITE_OPERATOR_ARITHMETIC) {
         // The arithmetic composite primitive can draw outside the bounding
         // box of its source images.
         const nsTArray<float>& coefficients = aComposite.mCoefficients;
         MOZ_ASSERT(coefficients.Length() == 4);
 
         // The calculation is:
@@ -1655,41 +1662,42 @@ nsIntRegion FilterSupport::PostFilterExt
         return region;
       }
       if (op == SVG_FECOMPOSITE_OPERATOR_IN) {
         return mInputExtents[0].Intersect(mInputExtents[1]);
       }
       return ResultChangeRegionForPrimitive(mDescription, mInputExtents);
     }
 
-    nsIntRegion match(const MergeAttributes& aMerge) {
+    nsIntRegion operator()(const MergeAttributes& aMerge) {
       return ResultChangeRegionForPrimitive(mDescription, mInputExtents);
     }
 
-    nsIntRegion match(const GaussianBlurAttributes& aGaussianBlur) {
+    nsIntRegion operator()(const GaussianBlurAttributes& aGaussianBlur) {
       return ResultChangeRegionForPrimitive(mDescription, mInputExtents);
     }
 
-    nsIntRegion match(const DropShadowAttributes& aDropShadow) {
+    nsIntRegion operator()(const DropShadowAttributes& aDropShadow) {
       return ResultChangeRegionForPrimitive(mDescription, mInputExtents);
     }
 
-    nsIntRegion match(const DiffuseLightingAttributes& aDiffuseLighting) {
+    nsIntRegion operator()(const DiffuseLightingAttributes& aDiffuseLighting) {
       return mDescription.PrimitiveSubregion();
     }
 
-    nsIntRegion match(const SpecularLightingAttributes& aSpecularLighting) {
+    nsIntRegion operator()(
+        const SpecularLightingAttributes& aSpecularLighting) {
       return mDescription.PrimitiveSubregion();
     }
 
-    nsIntRegion match(const ImageAttributes& aImage) {
+    nsIntRegion operator()(const ImageAttributes& aImage) {
       return mDescription.PrimitiveSubregion();
     }
 
-    nsIntRegion match(const ToAlphaAttributes& aToAlpha) {
+    nsIntRegion operator()(const ToAlphaAttributes& aToAlpha) {
       return ResultChangeRegionForPrimitive(mDescription, mInputExtents);
     }
   };
 
   return aDescription.Attributes().match(
       PrimitiveAttributesMatcher(aDescription, aInputExtents));
 }
 
@@ -1733,130 +1741,131 @@ static nsIntRegion SourceNeededRegionFor
         : mDescription(aDescription),
           mResultNeededRegion(aResultNeededRegion),
           mInputIndex(aInputIndex) {}
 
     const FilterPrimitiveDescription& mDescription;
     const nsIntRegion& mResultNeededRegion;
     const int32_t mInputIndex;
 
-    nsIntRegion match(const EmptyAttributes& aEmptyAttributes) {
+    nsIntRegion operator()(const EmptyAttributes& aEmptyAttributes) {
       return nsIntRegion();
     }
 
-    nsIntRegion match(const BlendAttributes& aBlend) {
+    nsIntRegion operator()(const BlendAttributes& aBlend) {
       return mResultNeededRegion;
     }
 
-    nsIntRegion match(const ColorMatrixAttributes& aColorMatrix) {
+    nsIntRegion operator()(const ColorMatrixAttributes& aColorMatrix) {
       return mResultNeededRegion;
     }
 
-    nsIntRegion match(const MorphologyAttributes& aMorphology) {
+    nsIntRegion operator()(const MorphologyAttributes& aMorphology) {
       Size radii = aMorphology.mRadii;
       int32_t rx = clamped(int32_t(ceil(radii.width)), 0, kMorphologyMaxRadius);
       int32_t ry =
           clamped(int32_t(ceil(radii.height)), 0, kMorphologyMaxRadius);
       return mResultNeededRegion.Inflated(nsIntMargin(ry, rx, ry, rx));
     }
 
-    nsIntRegion match(const FloodAttributes& aFlood) {
+    nsIntRegion operator()(const FloodAttributes& aFlood) {
       MOZ_CRASH("GFX: this shouldn't be called for filters without inputs");
       return nsIntRegion();
     }
 
-    nsIntRegion match(const TileAttributes& aTile) {
+    nsIntRegion operator()(const TileAttributes& aTile) {
       return IntRect(INT32_MIN / 2, INT32_MIN / 2, INT32_MAX, INT32_MAX);
     }
 
-    nsIntRegion match(const ComponentTransferAttributes& aComponentTransfer) {
+    nsIntRegion operator()(
+        const ComponentTransferAttributes& aComponentTransfer) {
       return mResultNeededRegion;
     }
 
-    nsIntRegion match(const OpacityAttributes& aOpacity) {
+    nsIntRegion operator()(const OpacityAttributes& aOpacity) {
       return mResultNeededRegion;
     }
 
-    nsIntRegion match(const ConvolveMatrixAttributes& aConvolveMatrix) {
+    nsIntRegion operator()(const ConvolveMatrixAttributes& aConvolveMatrix) {
       Size kernelUnitLength = aConvolveMatrix.mKernelUnitLength;
       IntSize kernelSize = aConvolveMatrix.mKernelSize;
       IntPoint target = aConvolveMatrix.mTarget;
       nsIntMargin m(
           ceil(kernelUnitLength.width * (kernelSize.width - target.x - 1)),
           ceil(kernelUnitLength.height * (kernelSize.height - target.y - 1)),
           ceil(kernelUnitLength.width * (target.x)),
           ceil(kernelUnitLength.height * (target.y)));
       return mResultNeededRegion.Inflated(m);
     }
 
-    nsIntRegion match(const OffsetAttributes& aOffset) {
+    nsIntRegion operator()(const OffsetAttributes& aOffset) {
       IntPoint offset = aOffset.mValue;
       return mResultNeededRegion.MovedBy(-nsIntPoint(offset.x, offset.y));
     }
 
-    nsIntRegion match(const DisplacementMapAttributes& aDisplacementMap) {
+    nsIntRegion operator()(const DisplacementMapAttributes& aDisplacementMap) {
       if (mInputIndex == 1) {
         return mResultNeededRegion;
       }
       int32_t scale = ceil(std::abs(aDisplacementMap.mScale));
       return mResultNeededRegion.Inflated(
           nsIntMargin(scale, scale, scale, scale));
     }
 
-    nsIntRegion match(const TurbulenceAttributes& aTurbulence) {
+    nsIntRegion operator()(const TurbulenceAttributes& aTurbulence) {
       MOZ_CRASH("GFX: this shouldn't be called for filters without inputs");
       return nsIntRegion();
     }
 
-    nsIntRegion match(const CompositeAttributes& aComposite) {
+    nsIntRegion operator()(const CompositeAttributes& aComposite) {
       return mResultNeededRegion;
     }
 
-    nsIntRegion match(const MergeAttributes& aMerge) {
+    nsIntRegion operator()(const MergeAttributes& aMerge) {
       return mResultNeededRegion;
     }
 
-    nsIntRegion match(const GaussianBlurAttributes& aGaussianBlur) {
+    nsIntRegion operator()(const GaussianBlurAttributes& aGaussianBlur) {
       const Size& stdDeviation = aGaussianBlur.mStdDeviation;
       int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
       int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
       return mResultNeededRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
     }
 
-    nsIntRegion match(const DropShadowAttributes& aDropShadow) {
+    nsIntRegion operator()(const DropShadowAttributes& aDropShadow) {
       IntPoint offset = aDropShadow.mOffset;
       nsIntRegion offsetRegion =
           mResultNeededRegion.MovedBy(-nsIntPoint(offset.x, offset.y));
       Size stdDeviation = aDropShadow.mStdDeviation;
       int32_t dx = InflateSizeForBlurStdDev(stdDeviation.width);
       int32_t dy = InflateSizeForBlurStdDev(stdDeviation.height);
       nsIntRegion blurRegion =
           offsetRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
       blurRegion.Or(blurRegion, mResultNeededRegion);
       return blurRegion;
     }
 
-    nsIntRegion match(const SpecularLightingAttributes& aLighting) {
-      return match(
+    nsIntRegion operator()(const SpecularLightingAttributes& aLighting) {
+      return operator()(
           *(static_cast<const DiffuseLightingAttributes*>(&aLighting)));
     }
 
-    nsIntRegion match(const DiffuseLightingAttributes& aLighting) {
+    nsIntRegion operator()(const DiffuseLightingAttributes& aLighting) {
       Size kernelUnitLength = aLighting.mKernelUnitLength;
       int32_t dx = ceil(kernelUnitLength.width);
       int32_t dy = ceil(kernelUnitLength.height);
       return mResultNeededRegion.Inflated(nsIntMargin(dy, dx, dy, dx));
     }
 
-    nsIntRegion match(const ImageAttributes& aImage) {
+    nsIntRegion operator()(const ImageAttributes& aImage) {
       MOZ_CRASH("GFX: this shouldn't be called for filters without inputs");
       return nsIntRegion();
     }
 
-    nsIntRegion match(const ToAlphaAttributes& aToAlpha) {
+    nsIntRegion operator()(const ToAlphaAttributes& aToAlpha) {
       return mResultNeededRegion;
     }
   };
 
   return aDescription.Attributes().match(PrimitiveAttributesMatcher(
       aDescription, aResultNeededRegion, aInputIndex));
 }
 
--- a/ipc/glue/IPCMessageUtils.h
+++ b/ipc/glue/IPCMessageUtils.h
@@ -975,17 +975,17 @@ template <class... Ts>
 struct ParamTraits<mozilla::Variant<Ts...>> {
   typedef mozilla::Variant<Ts...> paramType;
   using Tag = typename mozilla::detail::VariantTag<Ts...>::Type;
 
   struct VariantWriter {
     Message* msg;
 
     template <class T>
-    void match(const T& t) {
+    void operator()(const T& t) {
       WriteParam(msg, t);
     }
   };
 
   static void Write(Message* msg, const paramType& param) {
     WriteParam(msg, param.tag);
     param.match(VariantWriter{msg});
   }
--- a/js/public/GCVariant.h
+++ b/js/public/GCVariant.h
@@ -114,17 +114,17 @@ struct GCPolicy<mozilla::Variant<Ts...>>
 
   static bool isValid(const mozilla::Variant<Ts...>& v) {
     return v.match(IsValidMatcher());
   }
 
  private:
   struct IsValidMatcher {
     template <typename T>
-    bool match(T& v) {
+    bool operator()(T& v) {
       return GCPolicy<T>::isValid(v);
     };
   };
 };
 
 }  // namespace JS
 
 namespace js {
--- a/js/src/frontend/EitherParser.h
+++ b/js/src/frontend/EitherParser.h
@@ -42,17 +42,17 @@ struct InvokeMemberFunction {
   }
 
  public:
   template <typename... ActualArgs>
   explicit InvokeMemberFunction(ActualArgs&&... actualArgs)
       : args{std::forward<ActualArgs>(actualArgs)...} {}
 
   template <class Parser>
-  auto match(Parser* parser)
+  auto operator()(Parser* parser)
       -> decltype(this->matchInternal(GetThis<Parser>::get(parser),
                                       std::index_sequence_for<Args...>{})) {
     return this->matchInternal(GetThis<Parser>::get(parser),
                                std::index_sequence_for<Args...>{});
   }
 };
 
 // |this|-computing templates.
@@ -83,31 +83,31 @@ template <class TokenStream>
 struct TokenStreamComputeLineAndColumn {
   static constexpr auto get() { return &TokenStream::computeLineAndColumn; }
 };
 
 // Generic matchers.
 
 struct ParseHandlerMatcher {
   template <class Parser>
-  frontend::FullParseHandler& match(Parser* parser) {
+  frontend::FullParseHandler& operator()(Parser* parser) {
     return parser->handler_;
   }
 };
 
 struct ParserSharedBaseMatcher {
   template <class Parser>
-  frontend::ParserSharedBase& match(Parser* parser) {
+  frontend::ParserSharedBase& operator()(Parser* parser) {
     return *static_cast<frontend::ParserSharedBase*>(parser);
   }
 };
 
 struct ErrorReporterMatcher {
   template <class Parser>
-  frontend::ErrorReporter& match(Parser* parser) {
+  frontend::ErrorReporter& operator()(Parser* parser) {
     return parser->tokenStream;
   }
 };
 
 }  // namespace detail
 
 namespace frontend {
 
--- a/js/src/vm/Compartment.h
+++ b/js/src/vm/Compartment.h
@@ -82,69 +82,73 @@ class CrossCompartmentKey {
     return wrapped.as<T>();
   }
 
   template <typename F>
   auto applyToWrapped(F f) {
     struct WrappedMatcher {
       F f_;
       explicit WrappedMatcher(F f) : f_(f) {}
-      auto match(JSObject*& obj) { return f_(&obj); }
-      auto match(JSString*& str) { return f_(&str); }
-      auto match(DebuggerAndScript& tpl) { return f_(&mozilla::Get<1>(tpl)); }
-      auto match(DebuggerAndLazyScript& tpl) {
+      auto operator()(JSObject*& obj) { return f_(&obj); }
+      auto operator()(JSString*& str) { return f_(&str); }
+      auto operator()(DebuggerAndScript& tpl) {
         return f_(&mozilla::Get<1>(tpl));
       }
-      auto match(DebuggerAndObject& tpl) { return f_(&mozilla::Get<1>(tpl)); }
+      auto operator()(DebuggerAndLazyScript& tpl) {
+        return f_(&mozilla::Get<1>(tpl));
+      }
+      auto operator()(DebuggerAndObject& tpl) {
+        return f_(&mozilla::Get<1>(tpl));
+      }
     } matcher(f);
     return wrapped.match(matcher);
   }
 
   template <typename F>
   auto applyToDebugger(F f) {
     using ReturnType = decltype(f(static_cast<NativeObject**>(nullptr)));
     struct DebuggerMatcher {
       F f_;
       explicit DebuggerMatcher(F f) : f_(f) {}
-      ReturnType match(JSObject*& obj) { return ReturnType(); }
-      ReturnType match(JSString*& str) { return ReturnType(); }
-      ReturnType match(DebuggerAndScript& tpl) {
+      ReturnType operator()(JSObject*& obj) { return ReturnType(); }
+      ReturnType operator()(JSString*& str) { return ReturnType(); }
+      ReturnType operator()(DebuggerAndScript& tpl) {
         return f_(&mozilla::Get<0>(tpl));
       }
-      ReturnType match(DebuggerAndLazyScript& tpl) {
+      ReturnType operator()(DebuggerAndLazyScript& tpl) {
         return f_(&mozilla::Get<0>(tpl));
       }
-      ReturnType match(DebuggerAndObject& tpl) {
+      ReturnType operator()(DebuggerAndObject& tpl) {
         return f_(&mozilla::Get<0>(tpl));
       }
     } matcher(f);
     return wrapped.match(matcher);
   }
 
   JS::Compartment* compartment() {
     return applyToWrapped([](auto tp) { return (*tp)->maybeCompartment(); });
   }
 
   struct Hasher : public DefaultHasher<CrossCompartmentKey> {
     struct HashFunctor {
-      HashNumber match(JSObject* obj) {
+      HashNumber operator()(JSObject* obj) {
         return DefaultHasher<JSObject*>::hash(obj);
       }
-      HashNumber match(JSString* str) {
+      HashNumber operator()(JSString* str) {
         return DefaultHasher<JSString*>::hash(str);
       }
-      HashNumber match(const DebuggerAndScript& tpl) {
+      HashNumber operator()(const DebuggerAndScript& tpl) {
         return DefaultHasher<NativeObject*>::hash(mozilla::Get<0>(tpl)) ^
                DefaultHasher<JSScript*>::hash(mozilla::Get<1>(tpl));
       }
-      HashNumber match(const DebuggerAndLazyScript& tpl) {
+      HashNumber operator()(const DebuggerAndLazyScript& tpl) {
         return DefaultHasher<NativeObject*>::hash(mozilla::Get<0>(tpl)) ^
                DefaultHasher<LazyScript*>::hash(mozilla::Get<1>(tpl));
       }
-      HashNumber match(const DebuggerAndObject& tpl) {
+      HashNumber operator()(const DebuggerAndObject& tpl) {
         return DefaultHasher<NativeObject*>::hash(mozilla::Get<0>(tpl)) ^
                DefaultHasher<JSObject*>::hash(mozilla::Get<1>(tpl)) ^
                (mozilla::Get<2>(tpl) << 5);
       }
     };
     static HashNumber hash(const CrossCompartmentKey& key) {
       return key.wrapped.match(HashFunctor());
     }
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -229,65 +229,69 @@ static void FinishOffThreadIonCompile(ji
   builder->script()
       ->runtimeFromAnyThread()
       ->jitRuntime()
       ->numFinishedBuildersRef(lock)++;
 }
 
 static JSRuntime* GetSelectorRuntime(const CompilationSelector& selector) {
   struct Matcher {
-    JSRuntime* match(JSScript* script) {
+    JSRuntime* operator()(JSScript* script) {
       return script->runtimeFromMainThread();
     }
-    JSRuntime* match(Realm* realm) { return realm->runtimeFromMainThread(); }
-    JSRuntime* match(Zone* zone) { return zone->runtimeFromMainThread(); }
-    JSRuntime* match(ZonesInState zbs) { return zbs.runtime; }
-    JSRuntime* match(JSRuntime* runtime) { return runtime; }
-    JSRuntime* match(AllCompilations all) { return nullptr; }
-    JSRuntime* match(CompilationsUsingNursery cun) { return cun.runtime; }
+    JSRuntime* operator()(Realm* realm) {
+      return realm->runtimeFromMainThread();
+    }
+    JSRuntime* operator()(Zone* zone) { return zone->runtimeFromMainThread(); }
+    JSRuntime* operator()(ZonesInState zbs) { return zbs.runtime; }
+    JSRuntime* operator()(JSRuntime* runtime) { return runtime; }
+    JSRuntime* operator()(AllCompilations all) { return nullptr; }
+    JSRuntime* operator()(CompilationsUsingNursery cun) { return cun.runtime; }
   };
 
   return selector.match(Matcher());
 }
 
 static bool JitDataStructuresExist(const CompilationSelector& selector) {
   struct Matcher {
-    bool match(JSScript* script) { return !!script->realm()->jitRealm(); }
-    bool match(Realm* realm) { return !!realm->jitRealm(); }
-    bool match(Zone* zone) { return !!zone->jitZone(); }
-    bool match(ZonesInState zbs) { return zbs.runtime->hasJitRuntime(); }
-    bool match(JSRuntime* runtime) { return runtime->hasJitRuntime(); }
-    bool match(AllCompilations all) { return true; }
-    bool match(CompilationsUsingNursery cun) {
+    bool operator()(JSScript* script) { return !!script->realm()->jitRealm(); }
+    bool operator()(Realm* realm) { return !!realm->jitRealm(); }
+    bool operator()(Zone* zone) { return !!zone->jitZone(); }
+    bool operator()(ZonesInState zbs) { return zbs.runtime->hasJitRuntime(); }
+    bool operator()(JSRuntime* runtime) { return runtime->hasJitRuntime(); }
+    bool operator()(AllCompilations all) { return true; }
+    bool operator()(CompilationsUsingNursery cun) {
       return cun.runtime->hasJitRuntime();
     }
   };
 
   return selector.match(Matcher());
 }
 
 static bool IonBuilderMatches(const CompilationSelector& selector,
                               jit::IonBuilder* builder) {
   struct BuilderMatches {
     jit::IonBuilder* builder_;
 
-    bool match(JSScript* script) { return script == builder_->script(); }
-    bool match(Realm* realm) { return realm == builder_->script()->realm(); }
-    bool match(Zone* zone) {
+    bool operator()(JSScript* script) { return script == builder_->script(); }
+    bool operator()(Realm* realm) {
+      return realm == builder_->script()->realm();
+    }
+    bool operator()(Zone* zone) {
       return zone == builder_->script()->zoneFromAnyThread();
     }
-    bool match(JSRuntime* runtime) {
+    bool operator()(JSRuntime* runtime) {
       return runtime == builder_->script()->runtimeFromAnyThread();
     }
-    bool match(AllCompilations all) { return true; }
-    bool match(ZonesInState zbs) {
+    bool operator()(AllCompilations all) { return true; }
+    bool operator()(ZonesInState zbs) {
       return zbs.runtime == builder_->script()->runtimeFromAnyThread() &&
              zbs.state == builder_->script()->zoneFromAnyThread()->gcState();
     }
-    bool match(CompilationsUsingNursery cun) {
+    bool operator()(CompilationsUsingNursery cun) {
       return cun.runtime == builder_->script()->runtimeFromAnyThread() &&
              !builder_->safeForMinorGC();
     }
   };
 
   return selector.match(BuilderMatches{builder});
 }
 
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -2315,22 +2315,22 @@ void SourceCompressionTask::workEncoding
 }
 
 struct SourceCompressionTask::PerformTaskWork {
   SourceCompressionTask* const task_;
 
   explicit PerformTaskWork(SourceCompressionTask* task) : task_(task) {}
 
   template <typename Unit>
-  void match(const ScriptSource::Uncompressed<Unit>&) {
+  void operator()(const ScriptSource::Uncompressed<Unit>&) {
     task_->workEncodingSpecific<Unit>();
   }
 
   template <typename T>
-  void match(const T&) {
+  void operator()(const T&) {
     MOZ_CRASH(
         "why are we compressing missing, already-compressed, or "
         "BinAST source?");
   }
 };
 
 void ScriptSource::performTaskWork(SourceCompressionTask* task) {
   MOZ_ASSERT(hasUncompressedSource());
--- a/js/src/vm/JSScript.h
+++ b/js/src/vm/JSScript.h
@@ -709,225 +709,227 @@ class ScriptSource {
   frontend::BinASTSourceMetadata* binASTSourceMetadata() const {
     MOZ_ASSERT(hasBinASTSource());
     return binASTMetadata_.get();
   }
 
  private:
   struct UncompressedDataMatcher {
     template <typename Unit>
-    const void* match(const Uncompressed<Unit>& u) {
+    const void* operator()(const Uncompressed<Unit>& u) {
       return u.units();
     }
 
     template <typename T>
-    const void* match(const T&) {
+    const void* operator()(const T&) {
       MOZ_CRASH(
           "attempting to access uncompressed data in a "
           "ScriptSource not containing it");
       return nullptr;
     }
   };
 
  public:
   template <typename Unit>
   const Unit* uncompressedData() {
     return static_cast<const Unit*>(data.match(UncompressedDataMatcher()));
   }
 
  private:
   struct CompressedDataMatcher {
     template <typename Unit>
-    char* match(const Compressed<Unit>& c) {
+    char* operator()(const Compressed<Unit>& c) {
       return const_cast<char*>(c.raw.chars());
     }
 
     template <typename T>
-    char* match(const T&) {
+    char* operator()(const T&) {
       MOZ_CRASH(
           "attempting to access compressed data in a ScriptSource "
           "not containing it");
       return nullptr;
     }
   };
 
  public:
   template <typename Unit>
   char* compressedData() {
     return data.match(CompressedDataMatcher());
   }
 
  private:
   struct BinASTDataMatcher {
-    void* match(const BinAST& b) { return const_cast<char*>(b.string.chars()); }
+    void* operator()(const BinAST& b) {
+      return const_cast<char*>(b.string.chars());
+    }
 
     void notBinAST() { MOZ_CRASH("ScriptSource isn't backed by BinAST data"); }
 
     template <typename T>
-    void* match(const T&) {
+    void* operator()(const T&) {
       notBinAST();
       return nullptr;
     }
   };
 
  public:
   void* binASTData() { return data.match(BinASTDataMatcher()); }
 
  private:
   struct HasUncompressedSource {
     template <typename Unit>
-    bool match(const Uncompressed<Unit>&) {
+    bool operator()(const Uncompressed<Unit>&) {
       return true;
     }
 
     template <typename Unit>
-    bool match(const Compressed<Unit>&) {
+    bool operator()(const Compressed<Unit>&) {
       return false;
     }
 
-    bool match(const BinAST&) { return false; }
-
-    bool match(const Missing&) { return false; }
+    bool operator()(const BinAST&) { return false; }
+
+    bool operator()(const Missing&) { return false; }
   };
 
  public:
   bool hasUncompressedSource() const {
     return data.match(HasUncompressedSource());
   }
 
   template <typename Unit>
   bool uncompressedSourceIs() const {
     MOZ_ASSERT(hasUncompressedSource());
     return data.is<Uncompressed<Unit>>();
   }
 
  private:
   struct HasCompressedSource {
     template <typename Unit>
-    bool match(const Compressed<Unit>&) {
+    bool operator()(const Compressed<Unit>&) {
       return true;
     }
 
     template <typename Unit>
-    bool match(const Uncompressed<Unit>&) {
+    bool operator()(const Uncompressed<Unit>&) {
       return false;
     }
 
-    bool match(const BinAST&) { return false; }
-
-    bool match(const Missing&) { return false; }
+    bool operator()(const BinAST&) { return false; }
+
+    bool operator()(const Missing&) { return false; }
   };
 
  public:
   bool hasCompressedSource() const { return data.match(HasCompressedSource()); }
 
   template <typename Unit>
   bool compressedSourceIs() const {
     MOZ_ASSERT(hasCompressedSource());
     return data.is<Compressed<Unit>>();
   }
 
  private:
   template <typename Unit>
   struct SourceTypeMatcher {
     template <template <typename C> class Data>
-    bool match(const Data<Unit>&) {
+    bool operator()(const Data<Unit>&) {
       return true;
     }
 
     template <template <typename C> class Data, typename NotUnit>
-    bool match(const Data<NotUnit>&) {
+    bool operator()(const Data<NotUnit>&) {
       return false;
     }
 
-    bool match(const BinAST&) {
+    bool operator()(const BinAST&) {
       MOZ_CRASH("doesn't make sense to ask source type of BinAST data");
       return false;
     }
 
-    bool match(const Missing&) {
+    bool operator()(const Missing&) {
       MOZ_CRASH("doesn't make sense to ask source type when missing");
       return false;
     }
   };
 
  public:
   template <typename Unit>
   bool hasSourceType() const {
     return data.match(SourceTypeMatcher<Unit>());
   }
 
  private:
   struct SourceCharSizeMatcher {
     template <template <typename C> class Data, typename Unit>
-    uint8_t match(const Data<Unit>& data) {
+    uint8_t operator()(const Data<Unit>& data) {
       static_assert(std::is_same<Unit, mozilla::Utf8Unit>::value ||
                         std::is_same<Unit, char16_t>::value,
                     "should only have UTF-8 or UTF-16 source char");
       return sizeof(Unit);
     }
 
-    uint8_t match(const BinAST&) {
+    uint8_t operator()(const BinAST&) {
       MOZ_CRASH("BinAST source has no source-char size");
       return 0;
     }
 
-    uint8_t match(const Missing&) {
+    uint8_t operator()(const Missing&) {
       MOZ_CRASH("missing source has no source-char size");
       return 0;
     }
   };
 
  public:
   uint8_t sourceCharSize() const { return data.match(SourceCharSizeMatcher()); }
 
  private:
   struct UncompressedLengthMatcher {
     template <typename Unit>
-    size_t match(const Uncompressed<Unit>& u) {
+    size_t operator()(const Uncompressed<Unit>& u) {
       return u.length();
     }
 
     template <typename Unit>
-    size_t match(const Compressed<Unit>& u) {
+    size_t operator()(const Compressed<Unit>& u) {
       return u.uncompressedLength;
     }
 
-    size_t match(const BinAST& b) { return b.string.length(); }
-
-    size_t match(const Missing& m) {
+    size_t operator()(const BinAST& b) { return b.string.length(); }
+
+    size_t operator()(const Missing& m) {
       MOZ_CRASH("ScriptSource::length on a missing source");
       return 0;
     }
   };
 
  public:
   size_t length() const {
     MOZ_ASSERT(hasSourceText() || hasBinASTSource());
     return data.match(UncompressedLengthMatcher());
   }
 
  private:
   struct CompressedLengthOrZeroMatcher {
     template <typename Unit>
-    size_t match(const Uncompressed<Unit>&) {
+    size_t operator()(const Uncompressed<Unit>&) {
       return 0;
     }
 
     template <typename Unit>
-    size_t match(const Compressed<Unit>& c) {
+    size_t operator()(const Compressed<Unit>& c) {
       return c.raw.length();
     }
 
-    size_t match(const BinAST&) {
+    size_t operator()(const BinAST&) {
       MOZ_CRASH("trying to get compressed length for BinAST data");
       return 0;
     }
 
-    size_t match(const Missing&) {
+    size_t operator()(const Missing&) {
       MOZ_CRASH("missing source data");
       return 0;
     }
   };
 
  public:
   size_t compressedLengthOrZero() const {
     return data.match(CompressedLengthOrZeroMatcher());
@@ -993,36 +995,36 @@ class ScriptSource {
     ScriptSource* const source_;
     SharedImmutableString& compressed_;
 
     SetCompressedSourceFromTask(ScriptSource* source,
                                 SharedImmutableString& compressed)
         : source_(source), compressed_(compressed) {}
 
     template <typename Unit>
-    void match(const Uncompressed<Unit>&) {
+    void operator()(const Uncompressed<Unit>&) {
       source_->setCompressedSource<Unit>(std::move(compressed_),
                                          source_->length());
     }
 
     template <typename Unit>
-    void match(const Compressed<Unit>&) {
+    void operator()(const Compressed<Unit>&) {
       MOZ_CRASH(
           "can't set compressed source when source is already "
           "compressed -- ScriptSource::tryCompressOffThread "
           "shouldn't have queued up this task?");
     }
 
-    void match(const BinAST&) {
+    void operator()(const BinAST&) {
       MOZ_CRASH(
           "doesn't make sense to set compressed source for BinAST "
           "data");
     }
 
-    void match(const Missing&) {
+    void operator()(const Missing&) {
       MOZ_CRASH(
           "doesn't make sense to set compressed source for "
           "missing source -- ScriptSource::tryCompressOffThread "
           "shouldn't have queued up this task?");
     }
   };
 
   void setCompressedSourceFromTask(SharedImmutableString compressed);
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -1293,26 +1293,26 @@ static inline bool captureIsSatisfied(JS
     JSContext* cx_;
     JSPrincipals* framePrincipals_;
     const JSAtom* frameSource_;
 
    public:
     Matcher(JSContext* cx, JSPrincipals* principals, const JSAtom* source)
         : cx_(cx), framePrincipals_(principals), frameSource_(source) {}
 
-    bool match(JS::FirstSubsumedFrame& target) {
+    bool operator()(JS::FirstSubsumedFrame& target) {
       auto subsumes = cx_->runtime()->securityCallbacks->subsumes;
       return (!subsumes || subsumes(target.principals, framePrincipals_)) &&
              (!target.ignoreSelfHosted ||
               frameSource_ != cx_->names().selfHosted);
     }
 
-    bool match(JS::MaxFrames& target) { return target.maxFrames == 1; }
+    bool operator()(JS::MaxFrames& target) { return target.maxFrames == 1; }
 
-    bool match(JS::AllFrames&) { return false; }
+    bool operator()(JS::AllFrames&) { return false; }
   };
 
   Matcher m(cx, principals, source);
   return capture.match(m);
 }
 
 bool SavedStacks::insertFrames(JSContext* cx, MutableHandleSavedFrame frame,
                                JS::StackCapture&& capture) {
@@ -1864,22 +1864,22 @@ bool ConcreteStackFrame<SavedFrame>::con
 // `JS::ubi::AtomOrTwoByteChars` string to a `JSAtom*`.
 struct MOZ_STACK_CLASS AtomizingMatcher {
   JSContext* cx;
   size_t length;
 
   explicit AtomizingMatcher(JSContext* cx, size_t length)
       : cx(cx), length(length) {}
 
-  JSAtom* match(JSAtom* atom) {
+  JSAtom* operator()(JSAtom* atom) {
     MOZ_ASSERT(atom);
     return atom;
   }
 
-  JSAtom* match(const char16_t* chars) {
+  JSAtom* operator()(const char16_t* chars) {
     MOZ_ASSERT(chars);
     return AtomizeChars(cx, chars, length);
   }
 };
 
 JS_PUBLIC_API bool ConstructSavedFrameStackSlow(
     JSContext* cx, JS::ubi::StackFrame& frame,
     MutableHandleObject outSavedFrameStack) {
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -1016,39 +1016,39 @@ LiveSavedFrameCache::FramePtr::create(Ab
     return FramePtr(afp.asRematerializedFrame());
   }
 
   MOZ_CRASH("unexpected frame type");
 }
 
 struct LiveSavedFrameCache::FramePtr::HasCachedMatcher {
   template <typename Frame>
-  bool match(Frame* f) const {
+  bool operator()(Frame* f) const {
     return f->hasCachedSavedFrame();
   }
 };
 
 inline bool LiveSavedFrameCache::FramePtr::hasCachedSavedFrame() const {
   return ptr.match(HasCachedMatcher());
 }
 
 struct LiveSavedFrameCache::FramePtr::SetHasCachedMatcher {
   template <typename Frame>
-  void match(Frame* f) {
+  void operator()(Frame* f) {
     f->setHasCachedSavedFrame();
   }
 };
 
 inline void LiveSavedFrameCache::FramePtr::setHasCachedSavedFrame() {
   ptr.match(SetHasCachedMatcher());
 }
 
 struct LiveSavedFrameCache::FramePtr::ClearHasCachedMatcher {
   template <typename Frame>
-  void match(Frame* f) {
+  void operator()(Frame* f) {
     f->clearHasCachedSavedFrame();
   }
 };
 
 inline void LiveSavedFrameCache::FramePtr::clearHasCachedSavedFrame() {
   ptr.match(ClearHasCachedMatcher());
 }
 
--- a/js/src/vm/UbiNode.cpp
+++ b/js/src/vm/UbiNode.cpp
@@ -67,50 +67,52 @@ struct CopyToBufferMatcher {
                                    size_t length) {
     size_t i = 0;
     for (; i < length; i++) {
       dest[i] = src[i];
     }
     return i;
   }
 
-  size_t match(JSAtom* atom) {
+  size_t operator()(JSAtom* atom) {
     if (!atom) {
       return 0;
     }
 
     size_t length = std::min(atom->length(), maxLength);
     JS::AutoCheckCannotGC noGC;
     return atom->hasTwoByteChars()
                ? copyToBufferHelper(atom->twoByteChars(noGC), destination,
                                     length)
                : copyToBufferHelper(atom->latin1Chars(noGC), destination,
                                     length);
   }
 
-  size_t match(const char16_t* chars) {
+  size_t operator()(const char16_t* chars) {
     if (!chars) {
       return 0;
     }
 
     size_t length = std::min(js_strlen(chars), maxLength);
     return copyToBufferHelper(chars, destination, length);
   }
 };
 
 size_t JS::ubi::AtomOrTwoByteChars::copyToBuffer(
     RangedPtr<char16_t> destination, size_t length) {
   CopyToBufferMatcher m(destination, length);
   return match(m);
 }
 
 struct LengthMatcher {
-  size_t match(JSAtom* atom) { return atom ? atom->length() : 0; }
+  size_t operator()(JSAtom* atom) { return atom ? atom->length() : 0; }
 
-  size_t match(const char16_t* chars) { return chars ? js_strlen(chars) : 0; }
+  size_t operator()(const char16_t* chars) {
+    return chars ? js_strlen(chars) : 0;
+  }
 };
 
 size_t JS::ubi::AtomOrTwoByteChars::length() {
   LengthMatcher m;
   return match(m);
 }
 
 size_t StackFrame::source(RangedPtr<char16_t> destination,
--- a/mfbt/Variant.h
+++ b/mfbt/Variant.h
@@ -5,20 +5,20 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* A template class for tagged unions. */
 
 #include <new>
 #include <stdint.h>
 
 #include "mozilla/Assertions.h"
-#include "mozilla/Move.h"
 #include "mozilla/OperatorNewExtensions.h"
 #include "mozilla/TemplateLib.h"
 #include "mozilla/TypeTraits.h"
+#include <utility>
 
 #ifndef mozilla_Variant_h
 #  define mozilla_Variant_h
 
 namespace IPC {
 template <typename T>
 struct ParamTraits;
 }  // namespace IPC
@@ -169,19 +169,18 @@ struct VariantImplementation<Tag, N, T> 
   }
 
   template <typename Variant>
   static bool equal(const Variant& aLhs, const Variant& aRhs) {
     return aLhs.template as<N>() == aRhs.template as<N>();
   }
 
   template <typename Matcher, typename ConcreteVariant>
-  static auto match(Matcher&& aMatcher, ConcreteVariant& aV)
-      -> decltype(aMatcher.match(aV.template as<N>())) {
-    return aMatcher.match(aV.template as<N>());
+  static decltype(auto) match(Matcher&& aMatcher, ConcreteVariant& aV) {
+    return aMatcher(aV.template as<N>());
   }
 };
 
 // VariantImplementation for some variant type T.
 template <typename Tag, size_t N, typename T, typename... Ts>
 struct VariantImplementation<Tag, N, T, Ts...> {
   // The next recursive VariantImplementation.
   using Next = VariantImplementation<Tag, N + 1, Ts...>;
@@ -224,32 +223,31 @@ struct VariantImplementation<Tag, N, T, 
       MOZ_ASSERT(aRhs.template is<N>());
       return aLhs.template as<N>() == aRhs.template as<N>();
     } else {
       return Next::equal(aLhs, aRhs);
     }
   }
 
   template <typename Matcher, typename ConcreteVariant>
-  static auto match(Matcher&& aMatcher, ConcreteVariant& aV)
-      -> decltype(aMatcher.match(aV.template as<N>())) {
+  static decltype(auto) match(Matcher&& aMatcher, ConcreteVariant& aV) {
     if (aV.template is<N>()) {
-      return aMatcher.match(aV.template as<N>());
+      return aMatcher(aV.template as<N>());
     } else {
       // If you're seeing compilation errors here like "no matching
       // function for call to 'match'" then that means that the
       // Matcher doesn't exhaust all variant types. There must exist a
-      // Matcher::match(T&) for every variant type T.
+      // Matcher::operator()(T&) for every variant type T.
       //
       // If you're seeing compilation errors here like "cannot
       // initialize return object of type <...> with an rvalue of type
-      // <...>" then that means that the Matcher::match(T&) overloads
+      // <...>" then that means that the Matcher::operator()(T&) overloads
       // are returning different types. They must all return the same
       // Matcher::ReturnType type.
-      return Next::match(aMatcher, aV);
+      return Next::match(std::forward<Matcher>(aMatcher), aV);
     }
   }
 };
 
 /**
  * AsVariantTemporary stores a value of type T to allow construction of a
  * Variant value via type inference. Because T is copied and there's no
  * guarantee that the copy can be elided, AsVariantTemporary is best used with
@@ -418,29 +416,35 @@ struct VariantIndex {
  *         return ...;
  *       } else if (v.is<B>()) {
  *         return ...;
  *       } else {
  *         return doSomething(v.as<C>()); // Forgot about case D!
  *       }
  *     }
  *
- *     // Good!
+ *     // Instead, a single function object (that can deal with all possible
+ *     // options) may be provided:
  *     struct FooMatcher
  *     {
  *       // The return type of all matchers must be identical.
- *       char* match(A& a) { ... }
- *       char* match(B& b) { ... }
- *       char* match(C& c) { ... }
- *       char* match(D& d) { ... } // Compile-time error to forget D!
+ *       char* operator()(A& a) { ... }
+ *       char* operator()(B& b) { ... }
+ *       char* operator()(C& c) { ... }
+ *       char* operator()(D& d) { ... } // Compile-time error to forget D!
  *     }
  *     char* foo(Variant<A, B, C, D>& v) {
  *       return v.match(FooMatcher());
  *     }
  *
+ *     // In some situations, a single generic lambda may also be appropriate:
+ *     char* foo(Variant<A, B, C, D>& v) {
+ *       return v.match([](auto&){...});
+ *     }
+ *
  * ## Examples
  *
  * A tree is either an empty leaf, or a node with a value and two children:
  *
  *     struct Leaf { };
  *
  *     template<typename T>
  *     struct Node
@@ -679,25 +683,24 @@ class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_
     MOZ_RELEASE_ASSERT(is<N>());
     return typename detail::Nth<N, Ts...>::Type(std::move(as<N>()));
   }
 
   // Exhaustive matching of all variant types on the contained value.
 
   /** Match on an immutable const reference. */
   template <typename Matcher>
-  auto match(Matcher&& aMatcher) const
-      -> decltype(Impl::match(aMatcher, *this)) {
-    return Impl::match(aMatcher, *this);
+  decltype(auto) match(Matcher&& aMatcher) const {
+    return Impl::match(std::forward<Matcher>(aMatcher), *this);
   }
 
   /** Match on a mutable non-const reference. */
   template <typename Matcher>
-  auto match(Matcher&& aMatcher) -> decltype(Impl::match(aMatcher, *this)) {
-    return Impl::match(aMatcher, *this);
+  decltype(auto) match(Matcher&& aMatcher) {
+    return Impl::match(std::forward<Matcher>(aMatcher), *this);
   }
 };
 
 /*
  * AsVariant() is used to construct a Variant<T,...> value containing the
  * provided T value using type inference. It can be used to construct Variant
  * values in expressions or return them from functions without specifying the
  * entire Variant type.
--- a/mfbt/tests/TestVariant.cpp
+++ b/mfbt/tests/TestVariant.cpp
@@ -367,19 +367,19 @@ static void testEquality() {
   MOZ_RELEASE_ASSERT(v6 == v6);
 }
 
 struct Describer {
   static const char* little;
   static const char* medium;
   static const char* big;
 
-  const char* match(const uint8_t&) { return little; }
-  const char* match(const uint32_t&) { return medium; }
-  const char* match(const uint64_t&) { return big; }
+  const char* operator()(const uint8_t&) { return little; }
+  const char* operator()(const uint32_t&) { return medium; }
+  const char* operator()(const uint64_t&) { return big; }
 };
 
 const char* Describer::little = "little";
 const char* Describer::medium = "medium";
 const char* Describer::big = "big";
 
 static void testMatching() {
   printf("testMatching\n");
@@ -399,16 +399,51 @@ static void testMatching() {
   const V& constRef2 = v2;
   const V& constRef3 = v3;
 
   MOZ_RELEASE_ASSERT(constRef1.match(desc) == Describer::little);
   MOZ_RELEASE_ASSERT(constRef2.match(desc) == Describer::medium);
   MOZ_RELEASE_ASSERT(constRef3.match(desc) == Describer::big);
 }
 
+static void testMatchingLambda() {
+  printf("testMatchingLambda\n");
+  using V = Variant<uint8_t, uint32_t, uint64_t>;
+
+  auto desc = [](auto& a) {
+    switch (sizeof(a)) {
+      case 1:
+        return Describer::little;
+      case 4:
+        return Describer::medium;
+      case 8:
+        return Describer::big;
+      default:
+        MOZ_RELEASE_ASSERT(false);
+        return "";
+    }
+  };
+
+  V v1(uint8_t(1));
+  V v2(uint32_t(2));
+  V v3(uint64_t(3));
+
+  MOZ_RELEASE_ASSERT(v1.match(desc) == Describer::little);
+  MOZ_RELEASE_ASSERT(v2.match(desc) == Describer::medium);
+  MOZ_RELEASE_ASSERT(v3.match(desc) == Describer::big);
+
+  const V& constRef1 = v1;
+  const V& constRef2 = v2;
+  const V& constRef3 = v3;
+
+  MOZ_RELEASE_ASSERT(constRef1.match(desc) == Describer::little);
+  MOZ_RELEASE_ASSERT(constRef2.match(desc) == Describer::medium);
+  MOZ_RELEASE_ASSERT(constRef3.match(desc) == Describer::big);
+}
+
 static void testRvalueMatcher() {
   printf("testRvalueMatcher\n");
   using V = Variant<uint8_t, uint32_t, uint64_t>;
   V v(uint8_t(1));
   MOZ_RELEASE_ASSERT(v.match(Describer()) == Describer::little);
 }
 
 int main() {
@@ -417,13 +452,14 @@ int main() {
   testDuplicate();
   testConstructionWithVariantType();
   testConstructionWithVariantIndex();
   testCopy();
   testMove();
   testDestructor();
   testEquality();
   testMatching();
+  testMatchingLambda();
   testRvalueMatcher();
 
   printf("TestVariant OK!\n");
   return 0;
 }
--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -907,44 +907,44 @@ class MOZ_STACK_CLASS PrefWrapper : publ
   // Types.
 
   bool IsType(PrefType aType) const { return Type() == aType; }
   bool IsTypeNone() const { return IsType(PrefType::None); }
   bool IsTypeString() const { return IsType(PrefType::String); }
   bool IsTypeInt() const { return IsType(PrefType::Int); }
   bool IsTypeBool() const { return IsType(PrefType::Bool); }
 
-#define FORWARD(retType, method)                                   \
-  retType method() const {                                         \
-    struct Matcher {                                               \
-      retType match(const Pref* aPref) { return aPref->method(); } \
-      retType match(SharedPref& aPref) { return aPref.method(); }  \
-    };                                                             \
-    return match(Matcher());                                       \
+#define FORWARD(retType, method)                                        \
+  retType method() const {                                              \
+    struct Matcher {                                                    \
+      retType operator()(const Pref* aPref) { return aPref->method(); } \
+      retType operator()(SharedPref& aPref) { return aPref.method(); }  \
+    };                                                                  \
+    return match(Matcher());                                            \
   }
 
   FORWARD(bool, DefaultChanged)
   FORWARD(bool, IsLocked)
   FORWARD(bool, IsSticky)
   FORWARD(bool, HasDefaultValue)
   FORWARD(bool, HasUserValue)
   FORWARD(const char*, Name)
   FORWARD(nsCString, NameString)
   FORWARD(PrefType, Type)
 #undef FORWARD
 
-#define FORWARD(retType, method)                                        \
-  retType method(PrefValueKind aKind = PrefValueKind::User) const {     \
-    struct Matcher {                                                    \
-      PrefValueKind mKind;                                              \
-                                                                        \
-      retType match(const Pref* aPref) { return aPref->method(mKind); } \
-      retType match(SharedPref& aPref) { return aPref.method(mKind); }  \
-    };                                                                  \
-    return match(Matcher{aKind});                                       \
+#define FORWARD(retType, method)                                             \
+  retType method(PrefValueKind aKind = PrefValueKind::User) const {          \
+    struct Matcher {                                                         \
+      PrefValueKind mKind;                                                   \
+                                                                             \
+      retType operator()(const Pref* aPref) { return aPref->method(mKind); } \
+      retType operator()(SharedPref& aPref) { return aPref.method(mKind); }  \
+    };                                                                       \
+    return match(Matcher{aKind});                                            \
   }
 
   FORWARD(bool, GetBoolValue)
   FORWARD(int32_t, GetIntValue)
   FORWARD(nsCString, GetStringValue)
   FORWARD(const char*, GetBareStringValue)
 #undef FORWARD
 
@@ -1294,21 +1294,21 @@ class PrefsIter {
     }
   }
 
  private:
 #define MATCH(type, ...)                                                \
   do {                                                                  \
     struct Matcher {                                                    \
       PrefsIter& mIter;                                                 \
-      type match(HashElem& pos) {                                       \
+      type operator()(HashElem& pos) {                                  \
         HashElem& end MOZ_MAYBE_UNUSED = mIter.mEnd.as<HashElem>();     \
         __VA_ARGS__;                                                    \
       }                                                                 \
-      type match(SharedElem& pos) {                                     \
+      type operator()(SharedElem& pos) {                                \
         SharedElem& end MOZ_MAYBE_UNUSED = mIter.mEnd.as<SharedElem>(); \
         __VA_ARGS__;                                                    \
       }                                                                 \
     };                                                                  \
     return mPos.match(Matcher{*this});                                  \
   } while (0);
 
   bool Done() { MATCH(bool, return pos == end); }
@@ -1955,45 +1955,39 @@ class nsPrefBranch final : public nsIPre
 
     // Use default move constructors, disallow copy constructors.
     PrefName(PrefName&& aOther) = default;
     PrefName& operator=(PrefName&& aOther) = default;
     PrefName(const PrefName&) = delete;
     PrefName& operator=(const PrefName&) = delete;
 
     struct PtrMatcher {
-      static const char* match(const char* aVal) { return aVal; }
-      static const char* match(const nsCString& aVal) { return aVal.get(); }
+      const char* operator()(const char* aVal) { return aVal; }
+      const char* operator()(const nsCString& aVal) { return aVal.get(); }
     };
 
     struct CStringMatcher {
       // Note: This is a reference, not an instance. It's used to pass our outer
       // method argument through to our matcher methods.
       nsACString& mStr;
 
-      void match(const char* aVal) { mStr.Assign(aVal); }
-      void match(const nsCString& aVal) { mStr.Assign(aVal); }
+      void operator()(const char* aVal) { mStr.Assign(aVal); }
+      void operator()(const nsCString& aVal) { mStr.Assign(aVal); }
     };
 
     struct LenMatcher {
-      static size_t match(const char* aVal) { return strlen(aVal); }
-      static size_t match(const nsCString& aVal) { return aVal.Length(); }
+      size_t operator()(const char* aVal) { return strlen(aVal); }
+      size_t operator()(const nsCString& aVal) { return aVal.Length(); }
     };
 
-    const char* get() const {
-      static PtrMatcher m;
-      return match(m);
-    }
+    const char* get() const { return match(PtrMatcher{}); }
 
     void get(nsACString& aStr) const { match(CStringMatcher{aStr}); }
 
-    size_t Length() const {
-      static LenMatcher m;
-      return match(m);
-    }
+    size_t Length() const { return match(LenMatcher{}); }
   };
 
   virtual ~nsPrefBranch();
 
   int32_t GetRootLength() const { return mPrefRoot.Length(); }
 
   nsresult GetDefaultFromPropertiesFile(const char* aPrefName,
                                         nsAString& aReturn);
--- a/toolkit/components/extensions/WebExtensionPolicy.cpp
+++ b/toolkit/components/extensions/WebExtensionPolicy.cpp
@@ -733,18 +733,20 @@ DocInfo::DocInfo(const URLInfo& aURL, ns
     : mURL(aURL), mObj(AsVariant(aLoadInfo)) {}
 
 DocInfo::DocInfo(nsPIDOMWindowOuter* aWindow)
     : mURL(aWindow->GetDocumentURI()), mObj(AsVariant(aWindow)) {}
 
 bool DocInfo::IsTopLevel() const {
   if (mIsTopLevel.isNothing()) {
     struct Matcher {
-      bool match(Window aWin) { return aWin->IsTopLevelWindow(); }
-      bool match(LoadInfo aLoadInfo) { return aLoadInfo->GetIsTopLevelLoad(); }
+      bool operator()(Window aWin) { return aWin->IsTopLevelWindow(); }
+      bool operator()(LoadInfo aLoadInfo) {
+        return aLoadInfo->GetIsTopLevelLoad();
+      }
     };
     mIsTopLevel.emplace(mObj.match(Matcher()));
   }
   return mIsTopLevel.ref();
 }
 
 bool WindowShouldMatchActiveTab(nsPIDOMWindowOuter* aWin) {
   if (aWin->IsTopLevelWindow()) {
@@ -773,50 +775,50 @@ bool WindowShouldMatchActiveTab(nsPIDOMW
 
   nsCOMPtr<nsPIDOMWindowOuter> parent = aWin->GetParent();
   MOZ_ASSERT(parent != nullptr);
   return WindowShouldMatchActiveTab(parent);
 }
 
 bool DocInfo::ShouldMatchActiveTabPermission() const {
   struct Matcher {
-    bool match(Window aWin) { return WindowShouldMatchActiveTab(aWin); }
-    bool match(LoadInfo aLoadInfo) { return false; }
+    bool operator()(Window aWin) { return WindowShouldMatchActiveTab(aWin); }
+    bool operator()(LoadInfo aLoadInfo) { return false; }
   };
   return mObj.match(Matcher());
 }
 
 uint64_t DocInfo::FrameID() const {
   if (mFrameID.isNothing()) {
     if (IsTopLevel()) {
       mFrameID.emplace(0);
     } else {
       struct Matcher {
-        uint64_t match(Window aWin) { return aWin->WindowID(); }
-        uint64_t match(LoadInfo aLoadInfo) {
+        uint64_t operator()(Window aWin) { return aWin->WindowID(); }
+        uint64_t operator()(LoadInfo aLoadInfo) {
           return aLoadInfo->GetOuterWindowID();
         }
       };
       mFrameID.emplace(mObj.match(Matcher()));
     }
   }
   return mFrameID.ref();
 }
 
 nsIPrincipal* DocInfo::Principal() const {
   if (mPrincipal.isNothing()) {
     struct Matcher {
       explicit Matcher(const DocInfo& aThis) : mThis(aThis) {}
       const DocInfo& mThis;
 
-      nsIPrincipal* match(Window aWin) {
+      nsIPrincipal* operator()(Window aWin) {
         RefPtr<Document> doc = aWin->GetDoc();
         return doc->NodePrincipal();
       }
-      nsIPrincipal* match(LoadInfo aLoadInfo) {
+      nsIPrincipal* operator()(LoadInfo aLoadInfo) {
         if (!(mThis.URL().InheritsPrincipal() ||
               aLoadInfo->GetForceInheritPrincipal())) {
           return nullptr;
         }
         if (auto principal = aLoadInfo->PrincipalToInherit()) {
           return principal;
         }
         return aLoadInfo->TriggeringPrincipal();
--- a/xpcom/components/nsComponentManager.cpp
+++ b/xpcom/components/nsComponentManager.cpp
@@ -184,21 +184,21 @@ namespace {
  * without caring about the difference.
  */
 class MOZ_STACK_CLASS EntryWrapper final {
  public:
   explicit EntryWrapper(nsFactoryEntry* aEntry) : mEntry(aEntry) {}
 
   explicit EntryWrapper(const StaticModule* aEntry) : mEntry(aEntry) {}
 
-#define MATCH(type, ifFactory, ifStatic)                \
-  struct Matcher {                                      \
-    type match(nsFactoryEntry* entry) { ifFactory; }    \
-    type match(const StaticModule* entry) { ifStatic; } \
-  };                                                    \
+#define MATCH(type, ifFactory, ifStatic)                     \
+  struct Matcher {                                           \
+    type operator()(nsFactoryEntry* entry) { ifFactory; }    \
+    type operator()(const StaticModule* entry) { ifStatic; } \
+  };                                                         \
   return mEntry.match((Matcher()))
 
   const nsID& CID() {
     MATCH(const nsID&, return *entry->mCIDEntry->cid, return entry->CID());
   }
 
   already_AddRefed<nsIFactory> GetFactory() {
     MATCH(already_AddRefed<nsIFactory>, return entry->GetFactory(),