Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 27 additions & 35 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8859,17 +8859,14 @@ 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(
*this, kind, type, protocol->getDeclaredInterfaceType(),
getConstraintLocator(locator));

addUnsolvedConstraint(conformance);
if (activate)
activateConstraint(conformance);

return SolutionKind::Solved;
}

Expand Down Expand Up @@ -9243,46 +9240,41 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(

if (isExpr<UnresolvedMemberExpr>(anchor) &&
req->is<LocatorPathElt::TypeParameterRequirement>()) {
auto *memberLoc = getConstraintLocator(anchor, path.front());

auto signature = path[path.size() - 2]
.castTo<LocatorPathElt::OpenedGeneric>()
.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;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) -> T { fatalError() }
static func genericWithReqs<T: Collection, Q>(_: T) -> Q where T.Element == Q { // expected-note {{required by static method 'genericWithReqs' where 'T' = '()'}}
static func genericWithReqs<T: Collection, Q>(_: T) -> Q where T.Element == Q { // expected-note 3 {{required by static method 'genericWithReqs' where 'T' = '()'}}
fatalError()
}
}
Expand Down Expand Up @@ -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}}
Expand All @@ -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
Expand Down Expand Up @@ -363,3 +367,18 @@ do {
func testSomeMarkerProto<T: SomeMarkerProto>(_: 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}}