From f6303a2bb370c9b5a625c73165d503d3b34f47cf Mon Sep 17 00:00:00 2001 From: doste Date: Sat, 26 Jul 2025 20:12:12 -0300 Subject: [PATCH 1/3] Add a fixit for missing @dynamicMemberLookup. Fix: #83344 --- lib/Sema/TypeCheckAttr.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 4a089d9a0a44a..6269cd20b6fa8 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -2106,6 +2106,7 @@ bool swift::isValidKeyPathDynamicMemberLookup(SubscriptDecl *decl, return bool(getKeyPathTypeForDynamicMemberLookup(decl, ignoreLabel)); } + /// The @dynamicMemberLookup attribute is only allowed on types that have at /// least one subscript member declared like this: /// @@ -2161,8 +2162,14 @@ visitDynamicMemberLookupAttr(DynamicMemberLookupAttr *attr) { return isValidDynamicMemberLookupSubscript(cand, /*ignoreLabel*/ true); }); - // If there were no potentially valid candidates, then throw an error. + // If there were no potentially valid candidates, then throw an error and emit a fix-it. if (newCandidates.empty()) { + + // Emit a fix-it to suggest the user to add a subscript method. + auto &d = ctx.Diags; + d.diagnose(decl->getLoc(), diag::add_subscript_method, type) + .fixItReplace(decl->getLoc(), "dynamicMember"); + emitInvalidTypeDiagnostic(attr->getLocation()); return; } From ec1f8b6af1448b0d5658931867a660a635ccb56c Mon Sep 17 00:00:00 2001 From: doste Date: Sat, 26 Jul 2025 22:57:46 -0300 Subject: [PATCH 2/3] Add NOTE 'add_subscript_method' --- include/swift/AST/DiagnosticsSema.def | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 6a32586c265c7..b0274e8a18629 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1727,6 +1727,9 @@ 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(add_subscript_method, none, + "add to %0 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", ()) From 81d2dcc784e75c138fcb7770d9fdca3f59cfe2f9 Mon Sep 17 00:00:00 2001 From: doste Date: Sat, 26 Jul 2025 22:58:18 -0300 Subject: [PATCH 3/3] Add a test for missing @dynamicMemberLookup --- test/attr/attr_dynamic_member_lookup.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/attr/attr_dynamic_member_lookup.swift b/test/attr/attr_dynamic_member_lookup.swift index c921c4aee0414..587d07abc5c4d 100644 --- a/test/attr/attr_dynamic_member_lookup.swift +++ b/test/attr/attr_dynamic_member_lookup.swift @@ -191,7 +191,7 @@ func NotAllowedOnFunc() {} // expected-error @+1 {{'@dynamicMemberLookup' requires 'InvalidBase' to have a 'subscript(dynamicMember:)' method that accepts either 'ExpressibleByStringLiteral' or a key path}} @dynamicMemberLookup -class InvalidBase {} +class InvalidBase {} // expected-note {{add to 'InvalidBase' a 'subscript(dynamicMember:)' method that accepts either 'ExpressibleByStringLiteral' or a key path}} class InvalidDerived : InvalidBase { subscript(dynamicMember: String) -> Int { get {}} } @@ -787,6 +787,7 @@ do { // https://github.com/apple/swift/issues/52957 + @dynamicMemberLookup struct S1_52957 { subscript(dynamicMember: String) -> String { // expected-error {{'@dynamicMemberLookup' requires 'S1_52957' to have a 'subscript(dynamicMember:)' method that accepts either 'ExpressibleByStringLiteral' or a key path}}