From 8d247100d826840cacd5cc2a815622800095dda3 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 20 Oct 2025 15:08:11 -0400 Subject: [PATCH 1/2] Sema: Add a couple of passing diagnostic tests to static_members_on_protocol_in_generic_context.swift It looks like we didn't test leading dot with instance members. --- ...c_members_on_protocol_in_generic_context.swift | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/Constraints/static_members_on_protocol_in_generic_context.swift b/test/Constraints/static_members_on_protocol_in_generic_context.swift index 7ef8a01ec0a7d..4c9f28ef4d81b 100644 --- a/test/Constraints/static_members_on_protocol_in_generic_context.swift +++ b/test/Constraints/static_members_on_protocol_in_generic_context.swift @@ -363,3 +363,18 @@ do { func testSomeMarkerProto(_: T) {} testSomeMarkerProto(.answer()) } + +// Make sure we diagnose something for instance properties as well +extension P { + var instanceProp: S { S() } +} + +extension P where Self == S { + var instanceProp2: S { S() } +} + +test(.instanceProp) +// expected-error@-1 {{instance member 'instanceProp' cannot be used on type 'P'}} +test(.instanceProp2) +// expected-error@-1 {{instance member 'instanceProp2' cannot be used on type 'P'}} +// expected-error@-2 {{property 'instanceProp2' requires the types 'Self' and 'S' be equivalent}} \ No newline at end of file From 1b6ac2c1d86a04e7713e46cfd1b9a293c4adb106 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 20 Oct 2025 15:09:06 -0400 Subject: [PATCH 2/2] Sema: Clean up leading dot fix logic in simplifyConformsToConstraint() Tests still pass without this code, including the tests I just added in the previous commit. --- lib/Sema/CSSimplify.cpp | 62 ++++++++----------- ...mbers_on_protocol_in_generic_context.swift | 10 ++- 2 files changed, 34 insertions(+), 38 deletions(-) diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 4cf84fecad1e8..7badd961f9776 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -8859,7 +8859,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint( return SolutionKind::Solved; } - auto formUnsolved = [&](bool activate = false) { + auto formUnsolved = [&]() { // If we're supposed to generate constraints, do so. if (flags.contains(TMF_GenerateConstraints)) { auto *conformance = Constraint::create( @@ -8867,9 +8867,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint( getConstraintLocator(locator)); addUnsolvedConstraint(conformance); - if (activate) - activateConstraint(conformance); - return SolutionKind::Solved; } @@ -9243,46 +9240,41 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint( if (isExpr(anchor) && req->is()) { + auto *memberLoc = getConstraintLocator(anchor, path.front()); + auto signature = path[path.size() - 2] .castTo() .getSignature(); auto requirement = signature.getRequirements()[req->getIndex()]; - auto *memberLoc = getConstraintLocator(anchor, path.front()); - auto overload = findSelectedOverloadFor(memberLoc); - - // To figure out what is going on here we need to wait until - // member overload is set in the constraint system. - if (!overload) { - // If it's not allowed to generate new constraints - // there is no way to control re-activation, so this - // check has to fail. - if (!flags.contains(TMF_GenerateConstraints)) - return SolutionKind::Error; + auto attemptInvalidStaticMemberRefOnMetatypeFix = [&]() { + // If the failed requirement isn't the first generic parameter, + // it can't be a static member reference on a protocol metatype. + if (!requirement.getFirstType()->isEqual(getASTContext().TheSelfType)) + return false; - return formUnsolved(/*activate=*/true); - } + // If we don't know the overload yet, conservatively assume it's + // a static member reference on a protocol metatype. + auto overload = findSelectedOverloadFor(memberLoc); + if (!overload) + return true; - auto *memberRef = overload->choice.getDeclOrNull(); - if (!memberRef) - return SolutionKind::Error; + auto *decl = overload->choice.getDeclOrNull(); + if (!decl) + return true; - // If this is a `Self` conformance requirement from a static member - // reference on a protocol metatype, let's produce a tailored diagnostic. - if (memberRef->isStatic()) { - if (hasFixFor(memberLoc, - FixKind::AllowInvalidStaticMemberRefOnProtocolMetatype)) - return SolutionKind::Solved; + // Otherwise, we can do a precise check. + if (!decl->isStatic()) + return false; - if (auto *protocolDecl = - memberRef->getDeclContext()->getSelfProtocolDecl()) { - auto selfTy = protocolDecl->getSelfInterfaceType(); - if (selfTy->isEqual(requirement.getFirstType())) { - auto *fix = AllowInvalidStaticMemberRefOnProtocolMetatype::create( - *this, memberLoc); - return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved; - } - } + return decl->getDeclContext()->getSelfProtocolDecl() != nullptr; + }; + + if (attemptInvalidStaticMemberRefOnMetatypeFix()) { + auto *fix = AllowInvalidStaticMemberRefOnProtocolMetatype::create( + *this, memberLoc); + + return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved; } } diff --git a/test/Constraints/static_members_on_protocol_in_generic_context.swift b/test/Constraints/static_members_on_protocol_in_generic_context.swift index 4c9f28ef4d81b..6e1a7206121af 100644 --- a/test/Constraints/static_members_on_protocol_in_generic_context.swift +++ b/test/Constraints/static_members_on_protocol_in_generic_context.swift @@ -177,7 +177,7 @@ test_combo(.genericFn(42)) // expected-error {{global function 'test_combo' requ extension P { // expected-note 13 {{missing same-type requirement on 'Self'}} {{12-12= where Self == <#Type#>}} static func generic(_: T) -> T { fatalError() } - static func genericWithReqs(_: T) -> Q where T.Element == Q { // expected-note {{required by static method 'genericWithReqs' where 'T' = '()'}} + static func genericWithReqs(_: T) -> Q where T.Element == Q { // expected-note 3 {{required by static method 'genericWithReqs' where 'T' = '()'}} fatalError() } } @@ -246,7 +246,9 @@ test(.genericWithReqs([S()])) // expected-error {{contextual member reference to test(.genericWithReqs([42])) // expected-error@-1 {{contextual member reference to static method 'genericWithReqs' requires 'Self' constraint in the protocol extension}} test(.genericWithReqs(())) -// expected-error@-1 {{contextual member reference to static method 'genericWithReqs' requires 'Self' constraint in the protocol extension}} +// expected-error@-1 {{type '()' cannot conform to 'Collection'}} +// expected-note@-2 {{only concrete types such as structs, enums and classes can conform to protocols}} +// expected-error@-3 {{contextual member reference to static method 'genericWithReqs' requires 'Self' constraint in the protocol extension}} test_combo(.doesntExist) // expected-error {{reference to member 'doesntExist' cannot be resolved without a contextual type}} test_combo(.doesnt.exist()) // expected-error {{reference to member 'doesnt' cannot be resolved without a contextual type}} @@ -262,7 +264,9 @@ test_combo(.genericWithReqs([S()])) // expected-error {{contextual member refere test_combo(.genericWithReqs([42])) // expected-error@-1 {{contextual member reference to static method 'genericWithReqs' requires 'Self' constraint in the protocol extension}} test_combo(.genericWithReqs(())) -// expected-error@-1 {{contextual member reference to static method 'genericWithReqs' requires 'Self' constraint in the protocol extension}} +// expected-error@-1 {{type '()' cannot conform to 'Collection'}} +// expected-note@-2 {{only concrete types such as structs, enums and classes can conform to protocols}} +// expected-error@-3 {{contextual member reference to static method 'genericWithReqs' requires 'Self' constraint in the protocol extension}} protocol TestWithAssoc { associatedtype U