diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h
index 1d3b6cfe8d922..afe2a7fce1f77 100644
--- a/include/swift/AST/Decl.h
+++ b/include/swift/AST/Decl.h
@@ -62,6 +62,11 @@ namespace clang {
 class PointerAuthQualifier;
 } // end namespace clang
 
+namespace {
+class AttributeChecker;
+class DeclChecker;
+} // end anonymous namespace
+
 namespace swift {
   enum class AccessSemantics : unsigned char;
   class AccessorDecl;
@@ -509,9 +514,24 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl>, public Swi
     defaultArgumentKind : NumDefaultArgumentKindBits
   );
 
-  SWIFT_INLINE_BITFIELD(SubscriptDecl, VarDecl, 2,
-    StaticSpelling : 2
+  SWIFT_INLINE_BITFIELD(SubscriptDecl, VarDecl, 2+2,
+    StaticSpelling : 2,
+
+    /// Whether this decl has been evaluated as eligible to satisfy an
+    /// `@dynamicMemberLookup` requirement, and if eligible, the type of dynamic
+    /// member parameter it would use to satisfy the requirement.
+    ///
+    /// * 0b00 - not yet evaluated
+    /// * 0b01 - evaluated; not eligible
+    /// * 0b10 - evaluated; eligible, taking a `{{Reference}Writable}KeyPath`
+    ///          value
+    /// * 0b11 - evaluated; eligible, taking an `ExpressibleByStringLiteral`
+    ///          value
+    ///
+    /// i.e., 0 or `DynamicMemberLookupSubscriptEligibility` values + 1
+    DynamicMemberLookupEligibility : 2
   );
+
   SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+2+2+2+8+1+1+1+1+1+1,
     /// \see AbstractFunctionDecl::BodyKind
     BodyKind : 3,
@@ -7381,6 +7401,36 @@ enum class ObjCSubscriptKind {
   Keyed
 };
 
+/// Describes how a `SubscriptDecl` could be eligible to fulfill a
+/// `@dynamicMemberLookup` requirement.
+///
+/// `@dynamicMemberLookup` requires that a subscript:
+///
+///   1. Take an initial argument with an explicit `dynamicMember` argument
+///      label,
+///   2. Whose parameter type is non-variadic and is either
+///      * A `{{Reference}Writable}KeyPath`, or
+///      * A concrete type conforming to `ExpressibleByStringLiteral`,
+///   3. And whose following arguments (if any) are all either variadic or have
+///      a default value
+///
+/// Subscripts which don't meet these requirements strictly are not eligible.
+enum class DynamicMemberLookupSubscriptEligibility : uint8_t {
+  /// The `SubscriptDecl` cannot fulfill a `@dynamicMemberLookup` requirement.
+  ///
+  /// This can be due to a name mismatch, type mismatch, missing default
+  /// arguments, or otherwise.
+  None,
+
+  /// The `SubscriptDecl` can fulfill a `@dynamicMemberLookup` requirement with
+  /// a `{{Reference}Writable}KeyPath` dynamic member parameter.
+  KeyPath,
+
+  /// The `SubscriptDecl` can fulfill a `@dynamicMemberLookup` requirement with
+  /// an `ExpressibleByStringLiteral`-conforming dynamic member parameter.
+  String,
+};
+
 /// Declares a subscripting operator for a type.
 ///
 /// A subscript declaration is defined as a get/set pair that produces a
@@ -7410,6 +7460,8 @@ enum class ObjCSubscriptKind {
 /// signatures (indices and element type) are distinct.
 ///
 class SubscriptDecl : public GenericContext, public AbstractStorageDecl {
+  friend AttributeChecker;
+  friend DeclChecker;
   friend class ResultTypeRequest;
 
   SourceLoc StaticLoc;
@@ -7417,6 +7469,26 @@ class SubscriptDecl : public GenericContext, public AbstractStorageDecl {
   ParameterList *Indices;
   TypeLoc ElementTy;
 
+  // Evaluates and stores the decl's eligibility to fulfill
+  // `@dynamicMemberLookup` requirements. Given `Diags`, emits diagnostics for
+  // requirement mismatches; should only be passed in by `AttributeChecker` and
+  // `DeclChecker` within a type-checking context.
+  //
+  // Implemented in the type checker because checking the validity of a
+  // string-based dynamic member parameter requires checking conformance to
+  // `ExpressibleByStringLiteral`.
+  DynamicMemberLookupSubscriptEligibility
+  evaluateDynamicMemberLookupEligibility(DiagnosticEngine *Diags = nullptr);
+
+  // Maps `Bits.SubscriptDecl.DynamicMemberLookupEligibility` as stored to a
+  // `DynamicMemberLookupSubscriptEligibility`; `None` if `@dynamicMemberLookup`
+  // requirements have not been checked yet.
+  DynamicMemberLookupSubscriptEligibility
+  getStoredDynamicMemberLookupEligibility() const;
+
+  void setDynamicMemberLookupEligibility(
+      DynamicMemberLookupSubscriptEligibility eligibility);
+
   void setElementInterfaceType(Type type);
 
   SubscriptDecl(DeclName Name,
@@ -7435,6 +7507,11 @@ class SubscriptDecl : public GenericContext, public AbstractStorageDecl {
     setIndices(Indices);
   }
 
+  /// Returns the given as a `BoundGenericType` if it is a
+  /// `{{Reference}Writable}KeyPath` type which could be used to fulfill
+  /// `@dynamicMemberLookup` requirements; `nullptr` otherwise.
+  static BoundGenericType *getDynamicMemberParamTypeAsKeyPathType(Type paramTy);
+
 public:
   /// Factory function only for use by deserialization.
   static SubscriptDecl *createDeserialized(ASTContext &Context, DeclName Name,
@@ -7496,6 +7573,16 @@ class SubscriptDecl : public GenericContext, public AbstractStorageDecl {
   /// implies.
   ObjCSubscriptKind getObjCSubscriptKind() const;
 
+  /// Determines, caches, and returns whether the decl can be used to satisfy an
+  /// `@dynamicMemberLookup` requirement (and if so, how).
+  DynamicMemberLookupSubscriptEligibility
+  getDynamicMemberLookupSubscriptEligibility();
+
+  /// If the decl can be used to satisfy an `@dynamicMemberLookup` requirement
+  /// using a `{{Reference}Writable}KeyPath` dynamic member parameter, returns
+  /// the type of that parameter; `nullptr` otherwise.
+  BoundGenericType *getDynamicMemberLookupKeyPathType();
+
   SubscriptDecl *getOverriddenDecl() const {
     return cast_or_null<SubscriptDecl>(
                                   AbstractStorageDecl::getOverriddenDecl());
diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def
index 88755b944e6a5..32bc3a4f2eb1c 100644
--- a/include/swift/AST/DiagnosticsSema.def
+++ b/include/swift/AST/DiagnosticsSema.def
@@ -1700,9 +1700,14 @@ ERROR(invalid_dynamic_member_lookup_type,none,
       "'@dynamicMemberLookup' requires %0 to have a "
       "'subscript(dynamicMember:)' method that accepts either "
       "'ExpressibleByStringLiteral' or a key path", (Type))
-NOTE(invalid_dynamic_member_subscript, none,
-     "add an explicit argument label to this subscript to satisfy "
-     "the '@dynamicMemberLookup' requirement", ())
+NOTE(invalid_dynamic_member_subscript_missing_label, none,
+     "add an explicit argument label to this subscript to satisfy the "
+     "'@dynamicMemberLookup' requirement", ())
+NOTE(invalid_dynamic_member_subscript_out_of_order, none,
+     "'dynamicMember' argument must appear first in the argument list", ())
+NOTE(invalid_dynamic_member_subscript_missing_default, none,
+     "add a default value to this argument to satisfy the "
+     "'@dynamicMemberLookup' requirement", ())
 
 ERROR(string_index_not_integer,none,
       "String must not be indexed with %0, it has variable size elements",
diff --git a/include/swift/Sema/OverloadChoice.h b/include/swift/Sema/OverloadChoice.h
index 111703be8f50e..c18a918cd2cb2 100644
--- a/include/swift/Sema/OverloadChoice.h
+++ b/include/swift/Sema/OverloadChoice.h
@@ -206,7 +206,7 @@ class OverloadChoice {
   }
 
   /// Retrieve an overload choice for a declaration that was found via
-  /// dynamic member lookup. The `ValueDecl` is a `subscript(dynamicMember:)`
+  /// dynamic member lookup. The `ValueDecl` is a `subscript(dynamicMember:...)`
   /// method.
   static OverloadChoice getDynamicMemberLookup(Type base, ValueDecl *value,
                                                Identifier name,
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index d1e7c5f3e98f2..3c1c03bb52778 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -9641,11 +9641,55 @@ ObjCSubscriptKind SubscriptDecl::getObjCSubscriptKind() const {
   return ObjCSubscriptKind::Keyed;
 }
 
+DynamicMemberLookupSubscriptEligibility
+SubscriptDecl::getStoredDynamicMemberLookupEligibility() const {
+  return Bits.SubscriptDecl.DynamicMemberLookupEligibility
+             ? static_cast<DynamicMemberLookupSubscriptEligibility>(
+                   Bits.SubscriptDecl.DynamicMemberLookupEligibility - 1)
+             : DynamicMemberLookupSubscriptEligibility::None;
+}
+
+void SubscriptDecl::setDynamicMemberLookupEligibility(
+    DynamicMemberLookupSubscriptEligibility eligibility) {
+  Bits.SubscriptDecl.DynamicMemberLookupEligibility =
+      static_cast<uint8_t>(eligibility) + 1;
+}
+
 void SubscriptDecl::setElementInterfaceType(Type type) {
   getASTContext().evaluator.cacheOutput(ResultTypeRequest{this},
                                         std::move(type));
 }
 
+BoundGenericType *
+SubscriptDecl::getDynamicMemberParamTypeAsKeyPathType(Type paramTy) {
+  // Allow composing a key path type with a `Sendable` protocol as a way to
+  // express sendability requirements.
+  if (auto *existential = paramTy->getAs<ExistentialType>()) {
+    auto layout = existential->getExistentialLayout();
+
+    auto protocols = layout.getProtocols();
+    if (!llvm::all_of(protocols, [](ProtocolDecl *proto) {
+          return proto->isSpecificProtocol(KnownProtocolKind::Sendable) ||
+                 proto->getInvertibleProtocolKind();
+        })) {
+      return nullptr;
+    }
+
+    paramTy = layout.getSuperclass();
+    if (!paramTy) {
+      return nullptr;
+    }
+  }
+
+  if (!paramTy->isKeyPath() &&
+      !paramTy->isWritableKeyPath() &&
+      !paramTy->isReferenceWritableKeyPath()) {
+    return nullptr;
+  }
+
+  return paramTy->getAs<BoundGenericType>();
+}
+
 SubscriptDecl *
 SubscriptDecl::createDeserialized(ASTContext &Context, DeclName Name,
                                   StaticSpellingKind StaticSpelling,
@@ -9744,6 +9788,24 @@ SourceRange SubscriptDecl::getSignatureSourceRange() const {
   return getSubscriptLoc();
 }
 
+DynamicMemberLookupSubscriptEligibility
+SubscriptDecl::getDynamicMemberLookupSubscriptEligibility() {
+  evaluateDynamicMemberLookupEligibility();
+  return getStoredDynamicMemberLookupEligibility();
+}
+
+BoundGenericType *SubscriptDecl::getDynamicMemberLookupKeyPathType() {
+  if (getDynamicMemberLookupSubscriptEligibility() !=
+      DynamicMemberLookupSubscriptEligibility::KeyPath) {
+    return nullptr;
+  }
+
+  auto *indices = getIndices();
+  assert(indices->size() > 0 && "subscript must have at least one arg");
+  return getDynamicMemberParamTypeAsKeyPathType(
+    indices->get(0)->getInterfaceType());
+}
+
 DeclName AbstractFunctionDecl::getEffectiveFullName() const {
   if (getName())
     return getName();
diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp
index 7745773eb3aee..e7a518c26c99f 100644
--- a/lib/Sema/CSApply.cpp
+++ b/lib/Sema/CSApply.cpp
@@ -2368,10 +2368,12 @@ namespace {
                                   ->castTo<FunctionType>();
       auto appliedWrappers =
           solution.getAppliedPropertyWrappers(memberLoc->getAnchor());
+
       args = coerceCallArguments(
           args, fullSubscriptTy, subscriptRef, nullptr,
           locator.withPathElement(ConstraintLocator::ApplyArgument),
           appliedWrappers);
+
       if (!args)
         return nullptr;
 
@@ -2525,7 +2527,7 @@ namespace {
           LocatorPathElt::KeyPathDynamicMember(keyPathTy->getAnyNominal()));
       auto overload = solution.getOverloadChoice(componentLoc);
 
-      // Looks like there is a chain of implicit `subscript(dynamicMember:)`
+      // Looks like there is a chain of implicit `subscript(dynamicMember:...)`
       // calls necessary to resolve a member reference.
       switch (overload.choice.getKind()) {
       case OverloadChoiceKind::DynamicMemberLookup:
@@ -3585,6 +3587,51 @@ namespace {
       llvm_unreachable("Unhandled OverloadChoiceKind in switch.");
     }
 
+    /// Builds an argument list for making a call to the given
+    /// `@dynamicMemberLookup` subscript by inserting any necessary default
+    /// arguments.
+    ArgumentList *buildArgumentListForDynamicMemberLookupSubscript(
+        const SelectedOverload &overload, SourceLoc componentLoc,
+        ConstraintLocator *locator) {
+      assert(overload.choice.isAnyDynamicMemberLookup() &&
+             "Overload must be for dynamic member lookup");
+      auto *SD = cast<SubscriptDecl>(overload.choice.getDecl());
+      auto memberLoc = cs.getCalleeLocator(locator);
+      auto subscript = resolveConcreteDeclRef(SD, memberLoc);
+
+      // We specifically don't want the full type here to avoid losing parameter
+      // pack references.
+      auto fnType = overload.adjustedOpenedType->castTo<FunctionType>();
+
+      auto params = fnType->getParams();
+      SmallVector<Expr *, 4> args;
+      for (auto paramIdx : indices(params)) {
+        auto param = params[paramIdx];
+        auto paramTy =
+            simplifyType(param.getParameterType(/*forCanonical=*/true, &ctx));
+
+        Expr *argExpr;
+        if (paramIdx == 0) {
+          if (overload.choice.isKeyPathDynamicMemberLookup()) {
+            argExpr = buildKeyPathDynamicMemberArgExpr(paramTy, componentLoc,
+                                                       memberLoc);
+          } else {
+            auto fieldName =
+                overload.choice.getName().getBaseIdentifier().str();
+            argExpr = buildDynamicMemberLookupArgExpr(fieldName, componentLoc,
+                                                      paramTy);
+          }
+        } else {
+          argExpr = new (ctx) DefaultArgumentExpr(subscript, paramIdx,
+                                                  componentLoc, paramTy, dc);
+        }
+
+        args.emplace_back(cs.cacheType(argExpr));
+      }
+
+      return ArgumentList::forImplicitCallTo(SD->getIndices(), args, ctx);
+    }
+
     /// Form a type checked expression for the argument of a
     /// @dynamicMemberLookup subscript index parameter.
     Expr *buildDynamicMemberLookupArgExpr(StringRef name, SourceLoc loc,
@@ -3592,6 +3639,7 @@ namespace {
       // Build and type check the string literal index value to the specific
       // string type expected by the subscript.
       auto *nameExpr = new (ctx) StringLiteralExpr(name, loc, /*implicit*/true);
+      nameExpr->setType(literalTy);
       cs.setType(nameExpr, literalTy);
       return handleStringLiteralExpr(nameExpr);
     }
@@ -3601,49 +3649,21 @@ namespace {
                                       const SelectedOverload &overload,
                                       ConstraintLocator *memberLocator) {
       // Application of a DynamicMemberLookup result turns
-      // a member access of `x.foo` into x[dynamicMember: "foo"], or
-      // x[dynamicMember: KeyPath<T, U>]
-
-      // Figure out the expected type of the lookup parameter. We know the
-      // openedFullType will be "xType -> indexType -> resultType".  Dig out
-      // its index type.
-      auto paramTy = getTypeOfDynamicMemberIndex(overload);
-
-      Expr *argExpr = nullptr;
-      if (overload.choice.getKind() ==
-          OverloadChoiceKind::DynamicMemberLookup) {
-        // Build and type check the string literal index value to the specific
-        // string type expected by the subscript.
-        auto fieldName = overload.choice.getName().getBaseIdentifier().str();
-        argExpr = buildDynamicMemberLookupArgExpr(fieldName, nameLoc, paramTy);
-      } else {
-        argExpr =
-            buildKeyPathDynamicMemberArgExpr(paramTy, dotLoc, memberLocator);
-      }
-
-      if (!argExpr)
-        return nullptr;
+      // a member access of `x.foo` into `x[dynamicMember: "foo", ...]`, or
+      // `x[dynamicMember: KeyPath<T, U>, ...]`
+      auto componentLoc =
+          overload.choice.getKind() == OverloadChoiceKind::DynamicMemberLookup
+              ? nameLoc
+              : dotLoc;
+      auto *args = buildArgumentListForDynamicMemberLookupSubscript(
+          overload, componentLoc, memberLocator);
 
-      // Build an argument list.
-      auto *argList =
-          ArgumentList::forImplicitSingle(ctx, ctx.Id_dynamicMember, argExpr);
       // Build and return a subscript that uses this string as the index.
-      return buildSubscript(base, argList, cs.getConstraintLocator(expr),
+      return buildSubscript(base, args, cs.getConstraintLocator(expr),
                             memberLocator, /*isImplicit*/ true,
                             AccessSemantics::Ordinary, overload);
     }
 
-    Type getTypeOfDynamicMemberIndex(const SelectedOverload &overload) {
-      assert(overload.choice.isAnyDynamicMemberLookup());
-
-      auto declTy = solution.simplifyType(overload.adjustedOpenedFullType);
-      auto subscriptTy = declTy->castTo<FunctionType>()->getResult();
-      auto refFnType = subscriptTy->castTo<FunctionType>();
-      assert(refFnType->getParams().size() == 1 &&
-             "subscript always has one arg");
-      return refFnType->getParams()[0].getPlainType();
-    }
-
   public:
     Expr *visitUnresolvedDotExpr(UnresolvedDotExpr *expr) {
       return applyMemberRefExpr(expr, expr->getBase(), expr->getDotLoc(),
@@ -5445,23 +5465,14 @@ namespace {
       // Compute substitutions to refer to the member.
       auto ref = resolveConcreteDeclRef(subscript, memberLoc);
 
-      // If this is a @dynamicMemberLookup reference to resolve a property
-      // through the subscript(dynamicMember:) member, restore the
+      // If this is a `@dynamicMemberLookup` reference to resolve a property
+      // through the `subscript(dynamicMember:...)` member, restore the
       // openedType and origComponent to its full reference as if the user
       // wrote out the subscript manually.
       if (overload.choice.isAnyDynamicMemberLookup()) {
-        auto indexType = getTypeOfDynamicMemberIndex(overload);
-        Expr *argExpr = nullptr;
-        if (overload.choice.isKeyPathDynamicMemberLookup()) {
-          argExpr = buildKeyPathDynamicMemberArgExpr(indexType, componentLoc,
-                                                     memberLoc);
-        } else {
-          auto fieldName = overload.choice.getName().getBaseIdentifier().str();
-          argExpr = buildDynamicMemberLookupArgExpr(fieldName, componentLoc,
-                                                    indexType);
-        }
-        args = ArgumentList::forImplicitSingle(ctx, ctx.Id_dynamicMember,
-                                               argExpr);
+        args = buildArgumentListForDynamicMemberLookupSubscript(
+            overload, componentLoc, locator);
+
         // Record the implicit subscript expr's parameter bindings and matching
         // direction as `coerceCallArguments` requires them.
         solution.recordSingleArgMatchingChoice(locator);
diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp
index e021ce40f7a70..8be9a93911a52 100644
--- a/lib/Sema/CSDiagnostics.cpp
+++ b/lib/Sema/CSDiagnostics.cpp
@@ -2532,36 +2532,39 @@ AssignmentFailure::getMemberRef(ConstraintLocator *locator) const {
   if (!member)
     return std::nullopt;
 
-  if (!member->choice.isDecl())
+  // If the member is a subscript, it might be a dynamic member lookup access,
+  // in which case we need to peer through the keypath parameter to get the
+  // underlying member.
+  auto *SD = member->choice.isDecl()
+                 ? dyn_cast<SubscriptDecl>(member->choice.getDecl())
+                 : nullptr;
+  auto eligibility = SD ? SD->getDynamicMemberLookupSubscriptEligibility()
+                        : DynamicMemberLookupSubscriptEligibility::None;
+  switch (eligibility) {
+  case DynamicMemberLookupSubscriptEligibility::None:
+    // Not a decl, subscript, or dynamic member lookup subscript; stick with the
+    // existing overload choice.
     return member->choice;
 
-  auto *decl = member->choice.getDecl();
-  if (isa<SubscriptDecl>(decl) &&
-      isValidDynamicMemberLookupSubscript(cast<SubscriptDecl>(decl))) {
-    auto *subscript = cast<SubscriptDecl>(decl);
-    // If this is a keypath dynamic member lookup, we have to
-    // adjust the locator to find member referred by it.
-    if (isValidKeyPathDynamicMemberLookup(subscript)) {
-      // Type has a following format:
-      // `(Self) -> (dynamicMember: {Writable}KeyPath<T, U>) -> U`
-      auto *fullType = member->adjustedOpenedFullType->castTo<FunctionType>();
-      auto *fnType = fullType->getResult()->castTo<FunctionType>();
-
-      auto paramTy = fnType->getParams()[0].getPlainType();
-      auto keyPath = paramTy->getAnyNominal();
-      auto memberLoc = getConstraintLocator(
-          locator, LocatorPathElt::KeyPathDynamicMember(keyPath));
-
-      auto memberRef = getOverloadChoiceIfAvailable(memberLoc);
-      return memberRef ? std::optional<OverloadChoice>(memberRef->choice)
-                       : std::nullopt;
-    }
-
-    // If this is a string based dynamic lookup, there is no member declaration.
+  case DynamicMemberLookupSubscriptEligibility::String:
+    // There is no member declaration for string-based dynamic member lookup
+    // subscripts.
     return std::nullopt;
-  }
 
-  return member->choice;
+  case DynamicMemberLookupSubscriptEligibility::KeyPath: {
+    auto keyPathType = SD->getDynamicMemberLookupKeyPathType();
+    assert(keyPathType && "KeyPath-based dynamic member lookup subscripts must "
+                          "have a valid dynamic member type");
+
+    auto memberLoc = getConstraintLocator(
+        locator,
+        LocatorPathElt::KeyPathDynamicMember(keyPathType->getAnyNominal()));
+
+    auto memberRef = getOverloadChoiceIfAvailable(memberLoc);
+    return memberRef ? std::optional<OverloadChoice>(memberRef->choice)
+                     : std::nullopt;
+  }
+  }
 }
 
 Diag<StringRef> AssignmentFailure::findDeclDiagnostic(ASTContext &ctx,
diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp
index fd5e6b9842a97..cf5ca977ca43e 100644
--- a/lib/Sema/CSSimplify.cpp
+++ b/lib/Sema/CSSimplify.cpp
@@ -10539,20 +10539,23 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
     }
 
     // While looking for subscript choices it's possible to find
-    // `subscript(dynamicMember: {Writable}KeyPath)` on types
-    // marked as `@dynamicMemberLookup`, let's mark this candidate
-    // as representing "dynamic lookup" unless it's a direct call
-    // to such subscript (in that case label is expected to match).
-    if (auto *subscript = dyn_cast<SubscriptDecl>(cand)) {
-      if (memberLocator && instanceTy->hasDynamicMemberLookupAttribute() &&
-          isValidKeyPathDynamicMemberLookup(subscript)) {
-        auto *args = getArgumentList(memberLocator);
-
-        if (!(args && args->isUnary() &&
-              args->getLabel(0) == getASTContext().Id_dynamicMember)) {
-          return OverloadChoice::getDynamicMemberLookup(
-              baseTy, subscript, ctx.getIdentifier("subscript"),
-              /*isKeyPathBased=*/true);
+    // `subscript(dynamicMember: {Reference{Writable}}KeyPath, ...)` on types
+    // marked as `@dynamicMemberLookup`; let's mark this candidate as
+    // representing "dynamic lookup" unless it's a direct call to such subscript
+    // (in that case label is expected to match).
+    if (auto *SD = dyn_cast<SubscriptDecl>(cand)) {
+      if (memberLocator && instanceTy->hasDynamicMemberLookupAttribute()) {
+        if (SD->getDynamicMemberLookupSubscriptEligibility() ==
+            DynamicMemberLookupSubscriptEligibility::KeyPath) {
+          auto *args = getArgumentList(memberLocator);
+          auto isDirectCallToSubscript =
+              args && args->isUnary() &&
+              args->getLabel(0) == getASTContext().Id_dynamicMember;
+          if (!isDirectCallToSubscript) {
+            return OverloadChoice::getDynamicMemberLookup(
+                baseTy, SD, ctx.getIdentifier("subscript"),
+                /*isKeyPathBased=*/true);
+          }
         }
       }
     }
@@ -10714,7 +10717,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
   // or if all of the candidates come from conditional conformances (which
   // might not be applicable), and we are looking for members in a type with
   // the @dynamicMemberLookup attribute, then we resolve a reference to a
-  // `subscript(dynamicMember:)` method and pass the member name as a string
+  // `subscript(dynamicMember:...)` method and pass the member name as a string
   // parameter.
   if (constraintKind == ConstraintKind::ValueMember &&
       memberName.isSimpleName() && !memberName.isSpecial() &&
@@ -10725,33 +10728,50 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
          allFromConditionalConformances(*this, instanceTy, candidates)) &&
         !isSelfRecursiveKeyPathDynamicMemberLookup(*this, baseTy,
                                                    memberLocator)) {
-      auto &ctx = getASTContext();
 
-      // Recursively look up `subscript(dynamicMember:)` methods in this type.
-      DeclNameRef subscriptName(
-          { ctx, DeclBaseName::createSubscript(), { ctx.Id_dynamicMember } });
       auto subscripts = performMemberLookup(
-          constraintKind, subscriptName, baseTy, functionRefInfo, memberLocator,
-          includeInaccessibleMembers);
+          constraintKind, DeclNameRef::createSubscript(), baseTy,
+          functionRefInfo, memberLocator, includeInaccessibleMembers);
 
       // Reflect the candidates found as `DynamicMemberLookup` results.
       auto name = memberName.getBaseIdentifier();
       for (const auto &candidate : subscripts.ViableCandidates) {
         auto *SD = cast<SubscriptDecl>(candidate.getDecl());
-        bool isKeyPathBased = isValidKeyPathDynamicMemberLookup(SD);
+        bool isKeyPathBased;
+        switch (SD->getDynamicMemberLookupSubscriptEligibility()) {
+        case DynamicMemberLookupSubscriptEligibility::None:
+          continue;
+        case DynamicMemberLookupSubscriptEligibility::KeyPath:
+          isKeyPathBased = true;
+          break;
+        case DynamicMemberLookupSubscriptEligibility::String:
+          isKeyPathBased = false;
+          break;
+        }
 
-        if (isValidStringDynamicMemberLookup(SD, DC->getParentModule()) ||
-            isKeyPathBased)
-          result.addViable(OverloadChoice::getDynamicMemberLookup(
-              baseTy, SD, name, isKeyPathBased));
+        result.addViable(OverloadChoice::getDynamicMemberLookup(
+            baseTy, SD, name, isKeyPathBased));
       }
 
       for (auto index : indices(subscripts.UnviableCandidates)) {
         auto *SD =
             cast<SubscriptDecl>(subscripts.UnviableCandidates[index].getDecl());
-        auto choice = OverloadChoice::getDynamicMemberLookup(
-            baseTy, SD, name, isValidKeyPathDynamicMemberLookup(SD));
-        result.addUnviable(choice, subscripts.UnviableReasons[index]);
+
+        bool isKeyPathBased;
+        switch (SD->getDynamicMemberLookupSubscriptEligibility()) {
+        case DynamicMemberLookupSubscriptEligibility::None:
+          continue;
+        case DynamicMemberLookupSubscriptEligibility::KeyPath:
+          isKeyPathBased = true;
+          break;
+        case DynamicMemberLookupSubscriptEligibility::String:
+          isKeyPathBased = false;
+          break;
+        }
+
+        result.addUnviable(OverloadChoice::getDynamicMemberLookup(
+                               baseTy, SD, name, isKeyPathBased),
+                           subscripts.UnviableReasons[index]);
       }
     }
   }
diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp
index 7aea6720aaf22..33c098d09c8fc 100644
--- a/lib/Sema/ConstraintSystem.cpp
+++ b/lib/Sema/ConstraintSystem.cpp
@@ -3952,8 +3952,8 @@ ConstraintSystem::getArgumentInfoLocator(ConstraintLocator *locator) {
   if (auto *UME = getAsExpr<UnresolvedMemberExpr>(anchor))
     return getConstraintLocator(UME);
 
-  // All implicit x[dynamicMember:] subscript calls can share the same argument
-  // list.
+  // All implicit `x[dynamicMember:...]` subscript calls can share the same
+  // argument list.
   if (locator->findLast<LocatorPathElt::ImplicitDynamicMemberSubscript>()) {
     return getConstraintLocator(
         ASTNode(), LocatorPathElt::ImplicitDynamicMemberSubscript());
diff --git a/lib/Sema/IDETypeCheckingRequests.cpp b/lib/Sema/IDETypeCheckingRequests.cpp
index 901879a3141e1..1ee06a8a933fe 100644
--- a/lib/Sema/IDETypeCheckingRequests.cpp
+++ b/lib/Sema/IDETypeCheckingRequests.cpp
@@ -258,7 +258,7 @@ TypeRelationCheckRequest::evaluate(Evaluator &evaluator,
 TypePair
 RootAndResultTypeOfKeypathDynamicMemberRequest::evaluate(Evaluator &evaluator,
                                               SubscriptDecl *subscript) const {
-  auto keyPathType = getKeyPathTypeForDynamicMemberLookup(subscript);
+  auto keyPathType = subscript->getDynamicMemberLookupKeyPathType();
   if (!keyPathType)
     return TypePair();
 
diff --git a/lib/Sema/LookupVisibleDecls.cpp b/lib/Sema/LookupVisibleDecls.cpp
index 80b6155ac732a..094ee3395e512 100644
--- a/lib/Sema/LookupVisibleDecls.cpp
+++ b/lib/Sema/LookupVisibleDecls.cpp
@@ -20,6 +20,7 @@
 #include "swift/AST/ASTContext.h"
 #include "swift/AST/ClangModuleLoader.h"
 #include "swift/AST/ConformanceLookup.h"
+#include "swift/AST/Decl.h"
 #include "swift/AST/GenericEnvironment.h"
 #include "swift/AST/GenericSignature.h"
 #include "swift/AST/ImportCache.h"
@@ -39,6 +40,7 @@
 #include "clang/Basic/Module.h"
 #include "clang/Lex/Preprocessor.h"
 #include "llvm/ADT/SetVector.h"
+#include <algorithm>
 #include <set>
 
 using namespace swift;
@@ -1119,21 +1121,18 @@ static void lookupVisibleDynamicMemberLookupDecls(
   if (!baseType->hasDynamicMemberLookupAttribute())
     return;
 
-  auto &ctx = dc->getASTContext();
-
-  // Lookup the `subscript(dynamicMember:)` methods in this type.
-  DeclNameRef subscriptName(
-      { ctx, DeclBaseName::createSubscript(), { ctx.Id_dynamicMember} });
-
-  SmallVector<ValueDecl *, 2> subscripts;
-  dc->lookupQualified(baseType, subscriptName, loc,
+  // Fetch all subscripts which satisfy the `@dynamicMemberLookup` attribute.
+  SmallVector<ValueDecl *, 4> subscripts;
+  dc->lookupQualified(baseType, DeclNameRef::createSubscript(), loc,
                       NL_QualifiedDefault | NL_ProtocolMembers, subscripts);
+  (void)std::remove_if(subscripts.begin(), subscripts.end(), [](ValueDecl *VD) {
+    auto *SD = dyn_cast<SubscriptDecl>(VD);
+    return !SD || SD->getDynamicMemberLookupSubscriptEligibility() ==
+                      DynamicMemberLookupSubscriptEligibility::None;
+  });
 
   for (ValueDecl *VD : subscripts) {
-    auto *subscript = dyn_cast<SubscriptDecl>(VD);
-    if (!subscript)
-      continue;
-
+    auto *subscript = cast<SubscriptDecl>(VD);
     auto rootType = evaluateOrDefault(subscript->getASTContext().evaluator,
       RootTypeOfKeypathDynamicMemberRequest{subscript}, Type());
     if (rootType.isNull())
diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp
index cee993d42311c..720a4214e0898 100644
--- a/lib/Sema/TypeCheckAttr.cpp
+++ b/lib/Sema/TypeCheckAttr.cpp
@@ -27,6 +27,7 @@
 #include "swift/AST/ClangModuleLoader.h"
 #include "swift/AST/ConformanceLookup.h"
 #include "swift/AST/Decl.h"
+#include "swift/AST/DiagnosticEngine.h"
 #include "swift/AST/DiagnosticsParse.h"
 #include "swift/AST/DiagnosticsSema.h"
 #include "swift/AST/Effects.h"
@@ -45,6 +46,7 @@
 #include "swift/AST/TypeCheckRequests.h"
 #include "swift/AST/Types.h"
 #include "swift/Basic/Assertions.h"
+#include "swift/Basic/SourceLoc.h"
 #include "swift/Parse/Lexer.h"
 #include "swift/Parse/ParseDeclName.h"
 #include "swift/Sema/IDETypeChecking.h"
@@ -52,6 +54,7 @@
 #include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/Debug.h"
+#include <algorithm>
 #include <optional>
 
 using namespace swift;
@@ -2025,181 +2028,153 @@ visitDynamicCallableAttr(DynamicCallableAttr *attr) {
   }
 }
 
-static bool hasSingleNonVariadicParam(SubscriptDecl *decl,
-                                      Identifier expectedLabel,
-                                      bool ignoreLabel = false) {
-  auto *indices = decl->getIndices();
-  if (decl->isInvalid() || indices->size() != 1)
-    return false;
-
-  auto *index = indices->get(0);
-  if (index->isVariadic() || !index->hasInterfaceType())
-    return false;
-
-  if (ignoreLabel) {
-    return true;
+DynamicMemberLookupSubscriptEligibility
+SubscriptDecl::evaluateDynamicMemberLookupEligibility(DiagnosticEngine *Diags) {
+  if (Bits.SubscriptDecl.DynamicMemberLookupEligibility) {
+    return getStoredDynamicMemberLookupEligibility();
   }
 
-  return index->getArgumentName() == expectedLabel;
-}
-
-/// Returns true if the given subscript method is an valid implementation of
-/// the `subscript(dynamicMember:)` requirement for @dynamicMemberLookup.
-/// The method is given to be defined as `subscript(dynamicMember:)`.
-bool swift::isValidDynamicMemberLookupSubscript(SubscriptDecl *decl,
-                                                bool ignoreLabel) {
-  // It could be
-  // - `subscript(dynamicMember: {Writable}KeyPath<...>)`; or
-  // - `subscript(dynamicMember: String*)`
-  return isValidKeyPathDynamicMemberLookup(decl, ignoreLabel) ||
-         isValidStringDynamicMemberLookup(decl, ignoreLabel);
-}
+  auto eligibility = DynamicMemberLookupSubscriptEligibility::None;
+  [&] {
+    // If we have an explicit diagnostic engine, we'll output to it on error; if
+    // we don't then all queued diagnostics will get discarded.
+    DiagnosticQueue queue{Diags ? *Diags : getDiags(),
+                          /*emitOnDestruction=*/(bool)Diags};
+    queue.getDiags().diagnose(this, diag::invalid_dynamic_member_lookup_type,
+                              getDeclContext()->getDeclaredInterfaceType());
 
-bool swift::isValidStringDynamicMemberLookup(SubscriptDecl *decl,
-                                             bool ignoreLabel) {
-  auto &ctx = decl->getASTContext();
-  // There are two requirements:
-  // - The subscript method has exactly one, non-variadic parameter.
-  // - The parameter type conforms to `ExpressibleByStringLiteral`.
-  if (!hasSingleNonVariadicParam(decl, ctx.Id_dynamicMember,
-                                 ignoreLabel))
-    return false;
-
-  const auto *param = decl->getIndices()->get(0);
-  auto paramType = param->getTypeInContext();
-
-  // If this is `subscript(dynamicMember: String*)`
-  return TypeChecker::conformsToKnownProtocol(
-      paramType, KnownProtocolKind::ExpressibleByStringLiteral);
-}
+    if (isInvalid()) {
+      return;
+    }
 
-BoundGenericType *
-swift::getKeyPathTypeForDynamicMemberLookup(SubscriptDecl *decl,
-                                            bool ignoreLabel) {
-  auto &ctx = decl->getASTContext();
-  if (!hasSingleNonVariadicParam(decl, ctx.Id_dynamicMember,
-                                 ignoreLabel))
-    return nullptr;
+    auto *indices = getIndices();
+    if (indices->size() == 0) {
+      return;
+    }
 
-  auto paramTy = decl->getIndices()->get(0)->getInterfaceType();
+    auto isInvalid = false;
+    auto &ctx = getASTContext();
+    auto diagnosedOutOfOrder = false;
+    auto firstIndex = indices->get(0);
+    if (firstIndex->getArgumentName() != ctx.Id_dynamicMember) {
+      if (!Diags) {
+        // If we're not here to produce diagnostics during type-checking,
+        // there's no need to keep going.
+        return;
+      }
 
-  // Allow to compose key path type with a `Sendable` protocol as
-  // a way to express sendability requirement.
-  if (auto *existential = paramTy->getAs<ExistentialType>()) {
-    auto layout = existential->getExistentialLayout();
+      isInvalid = true;
+
+      // We can separately diagnose whether the `dynamicMember` parameter is out
+      // of order vs. whether we're missing a `dynamicMember` label altogether.
+      if (indices->size() > 1) {
+        for (auto idx : range(1, indices->size())) {
+          auto index = indices->get(idx);
+          if (index->getArgumentName() == ctx.Id_dynamicMember) {
+            queue.getDiags()
+                .diagnose(this,
+                          diag::invalid_dynamic_member_subscript_out_of_order)
+                .highlight(index->getSourceRange());
+            diagnosedOutOfOrder = true;
+            break;
+          }
+        }
+      }
 
-    auto protocols = layout.getProtocols();
-    if (!llvm::all_of(protocols,
-                      [&](ProtocolDecl *proto) {
-                        if (proto->isSpecificProtocol(KnownProtocolKind::Sendable))
-                          return true;
+      // If there is no argument label at all, we can offer a fix-it to insert
+      // it. Note that we intentionally don't want to emit a diagnostic if there
+      // _is_ a label, since it's clearly just not a dynamic member lookup
+      // subscript.
+      if (!diagnosedOutOfOrder && firstIndex->getParameterNameLoc().isValid() &&
+          firstIndex->getArgumentNameLoc().isInvalid()) {
+        queue.getDiags()
+            .diagnose(this,
+                      diag::invalid_dynamic_member_subscript_missing_label)
+            .highlight(firstIndex->getSourceRange())
+            .fixItInsert(firstIndex->getParameterNameLoc(), "dynamicMember ");
+      }
+    }
 
-                        if (proto->getInvertibleProtocolKind())
-                          return true;
+    for (auto index : *indices) {
+      if (!index->hasInterfaceType() ||
+          (index == firstIndex && index->isVariadic())) {
+        isInvalid = true;
+      }
 
-                        return false;
-                      })) {
-      return nullptr;
+      if (index != firstIndex &&
+          (!diagnosedOutOfOrder ||
+           index->getArgumentName() != ctx.Id_dynamicMember) &&
+          (!index->isDefaultArgument() && !index->isVariadic() &&
+           !isa<PackExpansionType>(
+               index->getInterfaceType()->getCanonicalType()))) {
+        queue.getDiags()
+            .diagnose(this,
+                      diag::invalid_dynamic_member_subscript_missing_default)
+            .highlight(index->getSourceRange())
+            .fixItInsertAfter(index->getEndLoc(), " = <#Default#>");
+        isInvalid = true;
+      }
     }
 
-    paramTy = layout.getSuperclass();
-    if (!paramTy)
-      return nullptr;
-  }
+    if (isInvalid) {
+      // There's no point in checking the `dynamicMember` argument type since
+      // we've already output diagnostics.
+      return;
+    }
 
-  if (!paramTy->isKeyPath() &&
-      !paramTy->isWritableKeyPath() &&
-      !paramTy->isReferenceWritableKeyPath()) {
-    return nullptr;
-  }
-  return paramTy->getAs<BoundGenericType>();
-}
+    if (TypeChecker::conformsToKnownProtocol(
+            firstIndex->getTypeInContext(),
+            KnownProtocolKind::ExpressibleByStringLiteral)) {
+      queue.clear();
+      eligibility = DynamicMemberLookupSubscriptEligibility::String;
+    } else if (getDynamicMemberParamTypeAsKeyPathType(
+                   firstIndex->getInterfaceType())) {
+      queue.clear();
+      eligibility = DynamicMemberLookupSubscriptEligibility::KeyPath;
+    }
+  }();
 
-bool swift::isValidKeyPathDynamicMemberLookup(SubscriptDecl *decl,
-                                              bool ignoreLabel) {
-  return bool(getKeyPathTypeForDynamicMemberLookup(decl, ignoreLabel));
+  setDynamicMemberLookupEligibility(eligibility);
+  return eligibility;
 }
 
 /// The @dynamicMemberLookup attribute is only allowed on types that have at
 /// least one subscript member declared like this:
 ///
-/// subscript<KeywordType: ExpressibleByStringLiteral, LookupValue>
-///   (dynamicMember name: KeywordType) -> LookupValue { get }
+/// subscript(dynamicMember name: T, ...) -> U
+///   (where T is a concrete type conforming to `ExpressibleByStringLiteral`)
+///
+///   or
+///
+/// subscript(dynamicMember name: {{Reference}Writable}KeyPath<T, U>, ...) -> V
 ///
 /// ... but doesn't care about the mutating'ness of the getter/setter.
 /// We just manually check the requirements here.
-void AttributeChecker::
-visitDynamicMemberLookupAttr(DynamicMemberLookupAttr *attr) {
+void AttributeChecker::visitDynamicMemberLookupAttr(
+    DynamicMemberLookupAttr *attr) {
   // This attribute is only allowed on nominal types.
   auto decl = cast<NominalTypeDecl>(D);
   auto type = decl->getDeclaredType();
-  auto &ctx = decl->getASTContext();
-
-  auto emitInvalidTypeDiagnostic = [&](const SourceLoc loc) {
-    diagnose(loc, diag::invalid_dynamic_member_lookup_type, type);
-    attr->setInvalid();
-  };
-
-  // Look up `subscript(dynamicMember:)` candidates.
-  DeclNameRef subscriptName(
-      { ctx, DeclBaseName::createSubscript(), { ctx.Id_dynamicMember } });
-  auto candidates = TypeChecker::lookupMember(decl, type, subscriptName);
-
-  if (!candidates.empty()) {
-    // If no candidates are valid, then reject one.
-    auto oneCandidate = candidates.front().getValueDecl();
-    candidates.filter([&](LookupResultEntry entry, bool isOuter) -> bool {
-      auto cand = cast<SubscriptDecl>(entry.getValueDecl());
-      return isValidDynamicMemberLookupSubscript(cand);
-    });
-
-    if (candidates.empty()) {
-      emitInvalidTypeDiagnostic(oneCandidate->getLoc());
-    }
-
-    return;
-  }
-
-  // If we couldn't find any candidates, it's likely because:
-  //
-  // 1. We don't have a subscript with `dynamicMember` label.
-  // 2. We have a subscript with `dynamicMember` label, but no argument label.
-  //
-  // Let's do another lookup using just the base name.
-  auto newCandidates =
+  auto candidates =
       TypeChecker::lookupMember(decl, type, DeclNameRef::createSubscript());
 
-  // Validate the candidates while ignoring the label.
-  newCandidates.filter([&](const LookupResultEntry entry, bool isOuter) {
-    auto cand = cast<SubscriptDecl>(entry.getValueDecl());
-    return isValidDynamicMemberLookupSubscript(cand, /*ignoreLabel*/ true);
-  });
-
-  // If there were no potentially valid candidates, then throw an error.
-  if (newCandidates.empty()) {
-    emitInvalidTypeDiagnostic(attr->getLocation());
-    return;
-  }
-
-  // For each candidate, emit a diagnostic. If we don't have an explicit
-  // argument label, then emit a fix-it to suggest the user to add one.
-  for (auto cand : newCandidates) {
-    auto SD = cast<SubscriptDecl>(cand.getValueDecl());
-    auto index = SD->getIndices()->get(0);
-    diagnose(SD, diag::invalid_dynamic_member_lookup_type, type);
-
-    // If we have something like `subscript(foo:)` then we want to insert
-    // `dynamicMember` before `foo`.
-    if (index->getParameterNameLoc().isValid() &&
-        index->getArgumentNameLoc().isInvalid()) {
-      diagnose(SD, diag::invalid_dynamic_member_subscript)
-          .highlight(index->getSourceRange())
-          .fixItInsert(index->getParameterNameLoc(), "dynamicMember ");
+  // If we find at least one valid candidate, we won't produce any diagnostics.
+  DiagnosticQueue queue{Ctx.Diags, /*emitOnDestruction=*/true};
+  if (candidates.empty()) {
+    queue.getDiags().diagnose(attr->getLocation(),
+                              diag::invalid_dynamic_member_lookup_type, type);
+  } else {
+    for (auto candidate : candidates) {
+      auto *SD = cast<SubscriptDecl>(candidate.getValueDecl());
+      if (SD->evaluateDynamicMemberLookupEligibility(&queue.getDiags()) !=
+          DynamicMemberLookupSubscriptEligibility::None) {
+        queue.clear();
+        return;
+      }
     }
   }
 
   attr->setInvalid();
-  return;
 }
 
 /// Get the innermost enclosing declaration for a declaration.
diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp
index f7fef359f9466..650b94fe5da7c 100644
--- a/lib/Sema/TypeCheckDeclPrimary.cpp
+++ b/lib/Sema/TypeCheckDeclPrimary.cpp
@@ -3011,10 +3011,11 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
     checkExplicitAvailability(SD);
 
     if (!checkOverrides(SD)) {
-      // If a subscript has an override attribute but does not override
-      // anything, complain.
       if (auto *OA = SD->getAttrs().getAttribute<OverrideAttr>()) {
-        if (!SD->getOverriddenDecl()) {
+        auto *overriddenDecl = SD->getOverriddenDecl();
+        if (!overriddenDecl) {
+          // If a subscript has an override attribute but does not override
+          // anything, complain.
           auto DC = SD->getDeclContext();
           auto isClassContext = DC->getSelfClassDecl() != nullptr;
           auto isStructOrEnumContext = DC->getSelfEnumDecl() != nullptr ||
@@ -3028,6 +3029,25 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
                 .highlight(OA->getLocation());
           }
           OA->setInvalid();
+        } else if (auto outerTy = DC->getDeclaredInterfaceType()) {
+          // This is an overridden subscript; if the outer type has
+          // `@dynamicMemberLookup` but isn't directly annotated with it (e.g.,
+          // it's inherited), its members won't go through
+          // `@dynamicMemberLookup` checking via `AttributeChecker`. We need to
+          // ensure that if the overridden decl was a valid dynamic member
+          // lookup subscript, this override remains valid.
+          if (outerTy->hasDynamicMemberLookupAttribute() &&
+              !outerTy->getAnyNominal()
+                   ->getAttrs()
+                   .hasAttribute<DynamicMemberLookupAttr>()) {
+            if (overriddenDecl->getDynamicMemberLookupSubscriptEligibility() !=
+                    DynamicMemberLookupSubscriptEligibility::None &&
+                SD->evaluateDynamicMemberLookupEligibility(
+                    &SD->getDiags()) ==
+                    DynamicMemberLookupSubscriptEligibility::None) {
+              SD->setInvalid();
+            }
+          }
         }
       }
     }
diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h
index e87f692218ad8..989eec502a86e 100644
--- a/lib/Sema/TypeChecker.h
+++ b/lib/Sema/TypeChecker.h
@@ -1276,40 +1276,6 @@ diag::RequirementKind getProtocolRequirementKind(ValueDecl *Requirement);
 bool isValidDynamicCallableMethod(FuncDecl *decl,
                                   bool hasKeywordArguments);
 
-/// Returns true if the given subscript method is an valid implementation of
-/// the `subscript(dynamicMember:)` requirement for @dynamicMemberLookup.
-/// The method is given to be defined as `subscript(dynamicMember:)`.
-bool isValidDynamicMemberLookupSubscript(SubscriptDecl *decl,
-                                         bool ignoreLabel = false);
-
-/// Returns true if the given subscript method is an valid implementation of
-/// the `subscript(dynamicMember:)` requirement for @dynamicMemberLookup.
-/// The method is given to be defined as `subscript(dynamicMember:)` which
-/// takes a single non-variadic parameter that conforms to
-/// `ExpressibleByStringLiteral` protocol.
-bool isValidStringDynamicMemberLookup(SubscriptDecl *decl,
-                                      bool ignoreLabel = false);
-
-/// Returns the KeyPath parameter type for a valid implementation of
-/// the `subscript(dynamicMember: {Writable}KeyPath<...>)` requirement for
-/// @dynamicMemberLookup.
-/// The method is given to be defined as `subscript(dynamicMember:)` which
-/// takes a single non-variadic parameter of `{Writable}KeyPath<T, U>` type.
-///
-/// Returns null if the given subscript is not a valid dynamic member lookup
-/// implementation.
-BoundGenericType *
-getKeyPathTypeForDynamicMemberLookup(SubscriptDecl *decl,
-                                     bool ignoreLabel = false);
-
-/// Returns true if the given subscript method is an valid implementation of
-/// the `subscript(dynamicMember: {Writable}KeyPath<...>)` requirement for
-/// @dynamicMemberLookup.
-/// The method is given to be defined as `subscript(dynamicMember:)` which
-/// takes a single non-variadic parameter of `{Writable}KeyPath<T, U>` type.
-bool isValidKeyPathDynamicMemberLookup(SubscriptDecl *decl,
-                                       bool ignoreLabel = false);
-
 /// Compute the wrapped value type for the given property that has attached
 /// property wrappers, when the backing storage is known to have the given type.
 ///
diff --git a/lib/Sema/TypeOfReference.cpp b/lib/Sema/TypeOfReference.cpp
index ef2606e8b93fb..c15217755b4f4 100644
--- a/lib/Sema/TypeOfReference.cpp
+++ b/lib/Sema/TypeOfReference.cpp
@@ -22,6 +22,7 @@
 #include "TypeCheckType.h"
 #include "TypeChecker.h"
 #include "swift/AST/ConformanceLookup.h"
+#include "swift/AST/ExtInfo.h"
 #include "swift/AST/GenericEnvironment.h"
 #include "swift/AST/Effects.h"
 #include "swift/AST/MacroDefinition.h"
@@ -1628,6 +1629,13 @@ DeclReferenceType ConstraintSystem::getTypeOfMemberReference(
         thrownErrorType = Type();
       }
 
+      // Mark the isolation if any parameter is isolated.
+      if (llvm::any_of(indices, [&](AnyFunctionType::Param p) {
+            return p.isIsolated();
+          })) {
+        info = info.withIsolation(FunctionTypeIsolation::forParameter());
+      }
+
       refType = FunctionType::get(indices, elementTy, info);
     } else {
       // Delay the adjustment for preconcurrency until after we've formed
@@ -1969,17 +1977,17 @@ void ConstraintSystem::bindOverloadType(const SelectedOverload &overload,
     }
   };
   auto addDynamicMemberSubscriptConstraints = [&](Type argTy, Type resultTy) {
-    // DynamicMemberLookup results are always a (dynamicMember: T1) -> T2
+    // DynamicMemberLookup results are always a `(dynamicMember: T1, ...) -> T2`
     // subscript.
     auto *fnTy = openedType->castTo<FunctionType>();
-    assert(fnTy->getParams().size() == 1 &&
-           "subscript always has one argument");
+    assert(fnTy->getParams().size() > 0 &&
+           "subscript always has at least one argument");
 
     auto *callLoc = getConstraintLocator(
         locator, LocatorPathElt::ImplicitDynamicMemberSubscript());
 
-    // Associate an argument list for the implicit x[dynamicMember:] subscript
-    // if we haven't already.
+    // Associate an argument list for the implicit `x[dynamicMember:...]`
+    // subscript if we haven't already.
     auto *argLoc = getArgumentInfoLocator(callLoc);
     if (ArgumentLists.find(argLoc) == ArgumentLists.end()) {
       auto *argList = ArgumentList::createImplicit(
@@ -2044,9 +2052,9 @@ void ConstraintSystem::bindOverloadType(const SelectedOverload &overload,
     if (!stringLiteral)
       return;
 
-    // Form constraints for a x[dynamicMember:] subscript with a string literal
-    // argument, where the overload type is bound to the result to model the
-    // fact that this a property access in the source.
+    // Form constraints for a `x[dynamicMember:...]` subscript with a string
+    // literal argument, where the overload type is bound to the result to model
+    // the fact that this a property access in the source.
     auto argTy = createTypeVariable(locator, /*options*/ 0);
     addConstraint(ConstraintKind::LiteralConformsTo, argTy,
                   stringLiteral->getDeclaredInterfaceType(), locator);
@@ -2055,8 +2063,8 @@ void ConstraintSystem::bindOverloadType(const SelectedOverload &overload,
   }
   case OverloadChoiceKind::KeyPathDynamicMemberLookup: {
     auto *fnType = openedType->castTo<FunctionType>();
-    assert(fnType->getParams().size() == 1 &&
-           "subscript always has one argument");
+    assert(fnType->getParams().size() > 0 &&
+           "subscript always has at least one argument");
     // Parameter type is KeyPath<T, U> where `T` is a root type
     // and U is a leaf type (aka member type).
     auto paramTy = fnType->getParams()[0].getPlainType();
@@ -2171,7 +2179,7 @@ void ConstraintSystem::bindOverloadType(const SelectedOverload &overload,
       // type into "leaf" directly.
       addConstraint(ConstraintKind::Equal, memberTy, leafTy, keyPathLoc);
 
-      // Form constraints for a x[dynamicMember:] subscript with a key path
+      // Form constraints for a `x[dynamicMember:...]` subscript with a key path
       // argument, where the overload type is bound to the result to model the
       // fact that this a property access in the source.
       addDynamicMemberSubscriptConstraints(/*argTy*/ paramTy, boundType);
diff --git a/test/attr/attr_dynamic_member_lookup.swift b/test/attr/attr_dynamic_member_lookup.swift
index c921c4aee0414..ca0d5f6ad4537 100644
--- a/test/attr/attr_dynamic_member_lookup.swift
+++ b/test/attr/attr_dynamic_member_lookup.swift
@@ -134,6 +134,127 @@ func testIUOResult(x: IUOResult) {
   // expected-note@-2{{force-unwrap}}
 }
 
+//===----------------------------------------------------------------------===//
+// Taking multiple arguments
+//===----------------------------------------------------------------------===//
+
+// Parameters after the initial `dynamicMember:` are valid as long as they
+// have default arguments or are variadic. These can be concrete or generic.
+
+protocol MultiArgDefaultValue {
+  static var defaultValue: Self { get }
+}
+
+@dynamicMemberLookup
+struct ValidMultiArg1 {
+  subscript<T, U, V: MultiArgDefaultValue, each W>(
+    dynamicMember member: KeyPath<T, U>,
+    magic: StaticString = #function,
+    generic: V = .defaultValue,
+    variadic: KeyPath<V, V>...,
+    parameterPack pack: repeat each W
+  ) -> KeyPath<T, U> {
+    get { member }
+    set {}
+  }
+}
+
+@dynamicMemberLookup
+struct ValidMultiArg2 {
+  subscript<T, U, V: MultiArgDefaultValue, each W>(
+    dynamicMember member: WritableKeyPath<T, U>,
+    magic: StaticString = #function,
+    generic: V = .defaultValue,
+    variadic: KeyPath<V, V>...,
+    parameterPack pack: repeat each W
+  ) -> WritableKeyPath<T, U> {
+    get { member }
+    set {}
+  }
+}
+
+@dynamicMemberLookup
+struct ValidMultiArg3 {
+  subscript<T, U, V: MultiArgDefaultValue, each W>(
+    dynamicMember member: ReferenceWritableKeyPath<T, U>,
+    magic: StaticString = #function,
+    generic: V = .defaultValue,
+    variadic: KeyPath<V, V>...,
+    parameterPack pack: repeat each W
+  ) -> WritableKeyPath<T, U> {
+    get { member }
+    set {}
+  }
+}
+
+@dynamicMemberLookup
+struct ValidMultiArg4 {
+  subscript<V: MultiArgDefaultValue, each W>(
+    dynamicMember member: String,
+    magic: StaticString = #function,
+    generic: V = .defaultValue,
+    variadic: KeyPath<V, V>...,
+    parameterPack pack: repeat each W
+  ) -> String {
+    get { member }
+    set {}
+  }
+}
+
+// Simultaneous overloads don't introduce ambiguity
+
+@dynamicMemberLookup
+struct ValidMultiArg5 {
+  subscript(dynamicMember member: StaticString) -> Int {
+    get { return 42 }
+    set {}
+  }
+
+  subscript<T, U, V: MultiArgDefaultValue, each W>(
+    dynamicMember member: KeyPath<T, U>,
+    magic: StaticString = #function,
+    generic: V = .defaultValue,
+    variadic: KeyPath<V, V>...,
+    parameterPack pack: repeat each W
+  ) -> KeyPath<T, U> {
+    get { member }
+    set {}
+  }
+
+  subscript<T, U, V: MultiArgDefaultValue, each W>(
+    dynamicMember member: WritableKeyPath<T, U>,
+    magic: StaticString = #function,
+    generic: V = .defaultValue,
+    variadic: KeyPath<V, V>...,
+    parameterPack pack: repeat each W
+  ) -> WritableKeyPath<T, U> {
+    get { member }
+    set {}
+  }
+
+  subscript<T, U, V: MultiArgDefaultValue, each W>(
+    dynamicMember member: ReferenceWritableKeyPath<T, U>,
+    magic: StaticString = #function,
+    generic: V = .defaultValue,
+    variadic: KeyPath<V, V>...,
+    parameterPack pack: repeat each W
+  ) -> WritableKeyPath<T, U> {
+    get { member }
+    set {}
+  }
+
+  subscript<V: MultiArgDefaultValue, each W>(
+    dynamicMember member: String,
+    magic: StaticString = #function,
+    generic: V = .defaultValue,
+    variadic: KeyPath<V, V>...,
+    parameterPack pack: repeat each W
+  ) -> String {
+    get { member }
+    set {}
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // Error cases
 //===----------------------------------------------------------------------===//
@@ -156,6 +277,25 @@ struct Invalid2 {
   }
 }
 
+// Given multiple arguments, all values after `dynamicMember:` must have a
+// default value.
+@dynamicMemberLookup
+struct InvalidMultiArg1 {
+  // expected-error@+1{{'@dynamicMemberLookup' requires 'InvalidMultiArg1' to have a 'subscript(dynamicMember:)' method that accepts either 'ExpressibleByStringLiteral' or a key path}}
+  subscript(dynamicMember member: String, magic: StaticString) -> String { // expected-note{{add a default value to this argument to satisfy the '@dynamicMemberLookup' requirement}} {{62-62= = <#Default#>}}
+    member
+  }
+}
+
+// `dynamicMember:` must still be the first argument among multiple.
+@dynamicMemberLookup
+struct InvalidMultiArg2 {
+  // expected-error@+1{{'@dynamicMemberLookup' requires 'InvalidMultiArg2' to have a 'subscript(dynamicMember:)' method that accepts either 'ExpressibleByStringLiteral' or a key path}}
+  subscript(magic: StaticString = #function, dynamicMember member: String) -> String { // expected-note{{'dynamicMember' argument must appear first in the argument list}}
+    member
+  }
+}
+
 // References to overloads are resolved just like normal subscript lookup:
 // they are either contextually disambiguated or are invalid.
 @dynamicMemberLookup
@@ -174,6 +314,81 @@ func testAmbiguity(a: Ambiguity) {
   _ = a.dynamism // expected-error {{ambiguous use of 'subscript(dynamicMember:)'}}
 }
 
+// References to overloads are also resolved just like normal subscript and
+// function lookup in the presence of overloads with default arguments: they are
+// either contextually disambiguated or are invalid, with a preference for
+// overloads with fewer arguments.
+@dynamicMemberLookup
+struct MultiArgAmbiguity {
+  subscript(dynamicMember member: String) -> String {
+    member
+  }
+
+  subscript(dynamicMember member: String, magic: StaticString = #function, variadic: Any...) -> Int {
+    42
+  }
+
+  subscript<V: MultiArgDefaultValue>(dynamicMember member: String, generic: V = .defaultValue, variadic: Any...) -> V {
+    generic
+  }
+
+  subscript(dynamicMember member: String, magic: StaticString = #function) -> Float {
+    42.0
+  }
+
+  subscript(dynamicMember member: String, magic: StaticString = #function) -> Double {
+    42.0
+  }
+
+  subscript<T, U>(dynamicMember member: KeyPath<T, U>, magic: StaticString = #function, variadic: Any...) -> KeyPath<T, U> {
+    member
+  }
+
+  subscript<T, U>(dynamicMember member: WritableKeyPath<T, U>, magic: StaticString = #function, variadic: Any...) -> WritableKeyPath<T, U> {
+    member
+  }
+
+  subscript<T, U>(dynamicMember member: ReferenceWritableKeyPath<T, U>, magic: StaticString = #function, variadic: Any...) -> ReferenceWritableKeyPath<T, U> {
+    member
+  }
+
+  subscript(dynamicMember member: String, magic: StaticString = #function, variadic: Any...) -> String {
+    member
+  }
+}
+
+extension Int: MultiArgDefaultValue {
+  static var defaultValue: Int { 0 }
+}
+
+func testMultiArgAmbiguity(a: MultiArgAmbiguity) {
+  // `subscript(dynamicMember: String) -> String` is preferred over other
+  // overloads as it has fewer parameters; even though the other subscripts can
+  // be ambiguous.
+  let _ = a.foo
+
+  // This is also true when selecting between specific overloads by return type:
+  // `subscript(dynamicMember:) -> String` is preferred over
+  // `subscript<V>(dynamicMember:magic:variadic:) -> String`.
+  let _: String = a.foo
+
+  // Normal disambiguation rules also apply to multi-arg subscripts:
+  // `subscript(dynamicMember:magic:variadic:) -> Int` is preferred over
+  // `subscript<V>(dynamicMember:generic:varadic:) -> V` because it's more
+  // specific.
+  let _: Int = a.foo
+
+  // Other normal ambiguity rules still apply too.
+  let _: Float = a.foo
+  let _: Double = a.foo
+  let _: any BinaryFloatingPoint = a.foo // expected-error{{ambiguous use of 'subscript(dynamicMember:_:)'}}
+
+  class Cls { var foo: Int = 42 }
+  let _: KeyPath<Cls, _> = a.foo
+  let _: WritableKeyPath<Cls, _> = a.foo
+  let _: ReferenceWritableKeyPath<Cls, _> = a.foo
+}
+
 // expected-error @+1 {{'@dynamicMemberLookup' attribute cannot be applied to this declaration}}
 @dynamicMemberLookup
 extension Int {
@@ -301,7 +516,22 @@ class BaseClass {
   subscript(dynamicMember member: String) -> Int {
     return 42
   }
+
+  subscript(dynamicMember member: String, magic: StaticString = #function) -> String {
+    return member
+  }
+
+  // These overloads are disfavored at callsites compared to the above and
+  // shouldn't introduce ambiguity.
+  subscript<each W>(dynamicMember member: String, magic: StaticString = #function, pack: repeat each W) -> Int {
+    return 42
+  }
+
+  subscript<each W>(dynamicMember member: String, magic: StaticString = #function, pack: repeat each W) -> String {
+    return member
+  }
 }
+
 class DerivedClass : BaseClass {}
 
 func testDerivedClass(x: BaseClass, y: DerivedClass) -> Int {
@@ -322,6 +552,31 @@ func testOverrideSubscript(a: BaseClass, b: DerivedClassWithSetter) {
   a.balboza = 12 // expected-error {{cannot assign through dynamic lookup property: 'a' is a 'let' constant}}
 }
 
+// Overriding with a different default value is valid.
+class DerivedClassWithOverriddenDefault : BaseClass {
+  override subscript(dynamicMember member: String, magic: StaticString = #fileID) -> String {
+    return member
+  }
+}
+
+func testOverrideSubscript(a: BaseClass, b: DerivedClassWithOverriddenDefault) {
+  let _: String = a.magic
+  let _: String = b.magic
+}
+
+// Overriding with a different default value is valid.
+class DerivedClassWithMissingDefault : BaseClass {
+  // expected-error@+1{{'@dynamicMemberLookup' requires 'DerivedClassWithMissingDefault' to have a 'subscript(dynamicMember:)' method that accepts either 'ExpressibleByStringLiteral' or a key path}}
+  override subscript(dynamicMember member: String, magic: StaticString) -> String { // expected-note{{add a default value to this argument to satisfy the '@dynamicMemberLookup' requirement}} {{71-71= = <#Default#>}}
+    return member
+  }
+}
+
+func testOverrideSubscript(a: BaseClass, b: DerivedClassWithMissingDefault) {
+  let _: String = a.magic
+  let _: String = b.magic
+}
+
 //===----------------------------------------------------------------------===//
 // Generics
 //===----------------------------------------------------------------------===//
@@ -332,6 +587,13 @@ struct SettableGeneric1<T> {
     get {}
     nonmutating set {}
   }
+
+  // This overload is disfavored at callsites compared to the above and
+  // shouldn't introduce ambiguity.
+  subscript<each W>(dynamicMember member: StaticString, variadic: T..., parameterPack pack: repeat each W) -> T? {
+    get {}
+    nonmutating set {}
+  }
 }
 
 func testGenericType<T>(a: SettableGeneric1<T>, b: T) -> T? {
@@ -350,6 +612,13 @@ struct SettableGeneric2<T> {
     get {}
     nonmutating set {}
   }
+
+  // This overload is disfavored at callsites compared to the above and
+  // shouldn't introduce ambiguity.
+  subscript<U: ExpressibleByStringLiteral, each W>(dynamicMember member: U, variadic: U..., parameterPack pack: repeat each W) -> T {
+    get {}
+    nonmutating set {}
+  }
 }
 
 func testGenericType2<T>(a: SettableGeneric2<T>, b: T) -> T? {
@@ -396,8 +665,17 @@ func testGenerics<S, T, P: GenericProtocol>(
 @dynamicMemberLookup
 class KP {
   subscript(dynamicMember member: String) -> Int { return 7 }
+
+  // This overload is disfavored at callsites compared to the above and
+  // shouldn't introduce ambiguity.
+  //
+  // We're using `String` here instead of `StaticString` since a `KeyPath`
+  // reference below requires arguments to be `Hashable` and `StaticString`
+  // isn't.
+  subscript(dynamicMember member: String, magic: String = #function) -> Int { return 42 }
 }
 _ = \KP.[dynamicMember: "hi"]
+_ = \KP.[dynamicMember: "hi", #fileID]
 _ = \KP.testLookup
 
 /* KeyPath based dynamic lookup */
@@ -429,6 +707,17 @@ struct Lens<T> {
     get { return Lens<U>(obj[keyPath: member]) }
     set { obj[keyPath: member] = newValue.obj }
   }
+
+  // These overloads are disfavored at callsites compared to the above and
+  // shouldn't introduce ambiguity.
+  subscript<U, each W>(dynamicMember member: KeyPath<T, U>, magic: StaticString = #function, pack: repeat each W) -> Lens<U> {
+    get { return Lens<U>(obj[keyPath: member]) }
+  }
+
+  subscript<U>(dynamicMember member: WritableKeyPath<T, U>, magic: StaticString = #function) -> Lens<U> {
+    get { return Lens<U>(obj[keyPath: member]) }
+    set { obj[keyPath: member] = newValue.obj }
+  }
 }
 
 var topLeft = Point(x: 0, y: 0)
@@ -538,6 +827,12 @@ class AMetatype<T> {
   subscript<U>(dynamicMember member: KeyPath<T.Type, U>) -> U {
     get { return value[keyPath: member] }
   }
+
+  // This overload is disfavored at callsites compared to the above and
+  // shouldn't introduce ambiguity.
+  subscript<U, each W>(dynamicMember member: KeyPath<T.Type, U>, magic: StaticString = #function, pack: repeat each W) -> U {
+    get { return value[keyPath: member] }
+  }
 }
 
 // Let's make sure that keypath dynamic member lookup
@@ -567,6 +862,12 @@ extension KeyPathLookup {
   subscript(dynamicMember member: KeyPath<T, Int>) -> Int! {
     get { return value[keyPath: member] }
   }
+
+  // This overload is disfavored at callsites compared to the above and
+  // shouldn't introduce ambiguity.
+  subscript<each W>(dynamicMember member: KeyPath<T, Int>, magic: StaticString = #function, pack: repeat each W) -> Int! {
+    get { return value[keyPath: member] }
+  }
 }
 
 class C<T> : KeyPathLookup {
@@ -594,6 +895,12 @@ class D<T> {
   subscript<U: Numeric>(dynamicMember member: KeyPath<T, U>) -> (U) -> U {
     get { return { offset in self.value[keyPath: member] + offset } }
   }
+
+  // This overload is disfavored at callsites compared to the above and
+  // shouldn't introduce ambiguity.
+  subscript<U: Numeric, each W>(dynamicMember member: KeyPath<T, U>, magic: StaticString = #function, pack: repeat each W) -> (U) -> U {
+    get { return { offset in self.value[keyPath: member] + offset } }
+  }
 }
 
 func faz(_ d: D<Point>) {
@@ -626,6 +933,26 @@ struct SubscriptLens<T> {
     get { return value[keyPath: member] }
     set { value[keyPath: member] = newValue }
   }
+
+  // These overloads are disfavored at callsites compared to the above and
+  // shouldn't introduce ambiguity.
+  subscript<each W>(foo: String, magic: StaticString = #function, pack: repeat each W) -> Int {
+    get { return 42 }
+  }
+
+  subscript(offset: Int, magic: StaticString = #function) -> Int {
+    get { return counter }
+    set { counter = counter + newValue }
+  }
+
+  subscript<U>(dynamicMember member: KeyPath<T, U>, magic: StaticString = #function) -> U! {
+    get { return value[keyPath: member] }
+  }
+
+  subscript<U>(dynamicMember member: WritableKeyPath<T, U>, magic: StaticString = #function) -> U {
+    get { return value[keyPath: member] }
+    set { value[keyPath: member] = newValue }
+  }
 }
 
 func keypath_with_subscripts(_ arr: SubscriptLens<[Int]>,
@@ -697,6 +1024,13 @@ struct SingleChoiceLens<T> {
     get { return obj[keyPath: member] }
     set { obj[keyPath: member] = newValue }
   }
+
+  // This overload is disfavored at callsites compared to the above and
+  // shouldn't introduce ambiguity.
+  subscript<U, each W>(dynamicMember member: WritableKeyPath<T, U>, magic: StaticString = #function, pack: repeat each W) -> U {
+    get { return obj[keyPath: member] }
+    set { obj[keyPath: member] = newValue }
+  }
 }
 
 // Make sure that disjunction filtering optimization doesn't
@@ -746,6 +1080,39 @@ func invalid_refs_through_dynamic_lookup() {
   }
 }
 
+//===----------------------------------------------------------------------===//
+// Isolation
+//===----------------------------------------------------------------------===//
+
+@dynamicMemberLookup
+struct Isolated {
+  subscript(dynamicMember member: String, isolation: isolated (any Actor)? = #isolation) -> String { // expected-note {{subscript declared here}}
+    return member
+  }
+}
+
+func nonIsolatedAccess(to value: Isolated) {
+  let _ = value.member // expected-error {{actor-isolated subscript 'subscript(dynamicMember:_:)' can not be referenced from a nonisolated context}}
+  Task { @MainActor in
+    // expected-error@+1 {{expression is 'async' but is not marked with 'await'}}
+    let _ = value.member // expected-note {{subscript access is 'async'}}
+
+    let _ = await value.member
+  }
+}
+
+@MainActor
+func isolatedAccess(to value: Isolated) async {
+  // expected-error@+1 {{expression is 'async' but is not marked with 'await'}}
+  let _ = value.member // expected-note {{subscript access is 'async'}}
+
+  let _ = await value.member
+}
+
+//===----------------------------------------------------------------------===//
+// Specific Issues
+//===----------------------------------------------------------------------===//
+
 // https://github.com/apple/swift/issues/52997
 
 final class C1_52997 {}
diff --git a/test/attr/attr_dynamic_member_lookup_default_args.swift b/test/attr/attr_dynamic_member_lookup_default_args.swift
new file mode 100644
index 0000000000000..c5f919099e75a
--- /dev/null
+++ b/test/attr/attr_dynamic_member_lookup_default_args.swift
@@ -0,0 +1,158 @@
+// RUN: %target-run-simple-swift %s
+// REQUIRES: executable_test
+
+//===----------------------------------------------------------------------===//
+// Magic Literals
+//===----------------------------------------------------------------------===//
+
+@dynamicMemberLookup
+struct Magic: Hashable {
+  let fileID: String
+  let file: String
+  let filePath: String
+  let function: String
+  let line: Int
+  let column: Int
+  let dsohandle: UnsafeRawPointer
+
+  init(
+    fileID: String = #fileID,
+    file: String = #file,
+    filePath: String = #filePath,
+    function: String = #function,
+    line: Int = #line,
+    column: Int = #column,
+    dsohandle: UnsafeRawPointer = #dsohandle
+  ) {
+    self.fileID = fileID
+    self.file = file
+    self.filePath = filePath
+    self.function = function
+    self.line = line
+    self.column = column
+    self.dsohandle = dsohandle
+  }
+
+  subscript(
+    dynamicMember member: String,
+    fileID: String = #fileID,
+    file: String = #file,
+    filePath: String = #filePath,
+    function: String = #function,
+    line: Int = #line,
+    column: Int = #column,
+    dsohandle: UnsafeRawPointer = #dsohandle
+  ) -> Magic {
+    return Magic(
+      fileID: fileID,
+      file: file,
+      filePath: filePath,
+      function: function,
+      line: line,
+      column: column,
+      dsohandle: dsohandle
+    )
+  }
+
+  func offset(lineBy lineOffset: Int, columnBy columnOffset: Int) -> Magic {
+    Magic(
+      fileID: fileID,
+      file: file,
+      filePath: filePath,
+      function: function,
+      line: line + lineOffset,
+      column: column + columnOffset,
+      dsohandle: dsohandle
+    )
+  }
+}
+
+/* ! ENSURE FORMATTERS ARE DISABLED TO PRESERVE WHITESPACE ! */
+let m1 = Magic() // 71:15
+let m2 = m1.member // 72:13
+assert(m1.offset(lineBy: +1, columnBy: -2) == m2)
+
+let m3 = m1
+  .member // 76:4
+assert(m1.offset(lineBy: +5, columnBy: -11) == m3)
+
+let m4 = m1
+  .
+  member // 81:3
+assert(m1.offset(lineBy: +10, columnBy: -12) == m4)
+
+//===----------------------------------------------------------------------===//
+// Inheritance
+//===----------------------------------------------------------------------===//
+
+@dynamicMemberLookup
+class Parent {
+  subscript(
+    dynamicMember member: String,
+    kept: String = #fileID,
+    overridden: String = #fileID
+  ) -> String {
+    [member, kept, overridden].joined(separator: ":")
+  }
+}
+
+@dynamicMemberLookup
+class Child: Parent {
+  override subscript(
+    dynamicMember member: String,
+    kept: String = #fileID,
+    overridden: String = #filePath
+  ) -> String {
+    [member, kept, overridden].joined(separator: ":")
+  }
+}
+
+assert(Parent().member == ["member", #fileID, #fileID].joined(separator: ":"))
+assert(Child().member == ["member", #fileID, #filePath].joined(separator: ":"))
+
+//===----------------------------------------------------------------------===//
+// Parameter Packs
+//===----------------------------------------------------------------------===//
+
+@dynamicMemberLookup
+struct Pack {
+  subscript<each T>(dynamicMember member: String, pack: repeat each T) -> (repeat each T) {
+    (repeat each pack)
+  }
+
+  subscript<each T, each U>(
+    dynamicMember member: String, pack1 pack1: repeat each T, pack2 pack2: repeat each U
+  ) -> Int {
+    var count = 0
+    for _ in repeat each pack1 {
+      count += 1
+    }
+
+    for _ in repeat each pack2 {
+      count += 1
+    }
+
+    return count
+  }
+}
+
+let p = Pack()
+assert(p.member == ())
+assert(p.member == 0)
+
+//===----------------------------------------------------------------------===//
+// Isolation
+//===----------------------------------------------------------------------===//
+
+@dynamicMemberLookup
+struct Isolated {
+  subscript(dynamicMember member: String, isolation: isolated (any Actor)? = #isolation) -> (any Actor)? {
+    isolation
+  }
+}
+
+Task<Void, Never>.startSynchronously { @MainActor in
+  let `actor` = await Isolated().actor
+  assert(`actor` === MainActor.shared)
+}
+