Skip to content

Commit d1ab178

Browse files
committed
[ConstraintSystem] Diagnose conformance failure with base of a static member lookup
Produce a tailored diagnostic when it has been established that base type of a static member reference on protocol metatype doesn't conform to a required protocol.
1 parent 5758ae2 commit d1ab178

File tree

2 files changed

+70
-44
lines changed

2 files changed

+70
-44
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 55 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5787,20 +5787,27 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
57875787
return SolutionKind::Solved;
57885788
}
57895789

5790-
// If we hit a type variable without a fixed type, we can't
5791-
// solve this yet.
5792-
if (type->isTypeVariableOrMember()) {
5790+
auto formUnsolved = [&](bool activate = false) {
57935791
// If we're supposed to generate constraints, do so.
57945792
if (flags.contains(TMF_GenerateConstraints)) {
5795-
addUnsolvedConstraint(
5796-
Constraint::create(*this, kind, type,
5797-
protocol->getDeclaredInterfaceType(),
5798-
getConstraintLocator(locator)));
5793+
auto *conformance = Constraint::create(
5794+
*this, kind, type, protocol->getDeclaredInterfaceType(),
5795+
getConstraintLocator(locator));
5796+
5797+
addUnsolvedConstraint(conformance);
5798+
if (activate)
5799+
activateConstraint(conformance);
5800+
57995801
return SolutionKind::Solved;
58005802
}
58015803

58025804
return SolutionKind::Unsolved;
5803-
}
5805+
};
5806+
5807+
// If we hit a type variable without a fixed type, we can't
5808+
// solve this yet.
5809+
if (type->isTypeVariableOrMember())
5810+
return formUnsolved();
58045811

58055812
auto *loc = getConstraintLocator(locator);
58065813

@@ -5922,7 +5929,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
59225929
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
59235930
}
59245931

5925-
if (path.back().is<LocatorPathElt::AnyRequirement>()) {
5932+
if (auto req = path.back().getAs<LocatorPathElt::AnyRequirement>()) {
59265933
// If this is a requirement associated with `Self` which is bound
59275934
// to `Any`, let's consider this "too incorrect" to continue.
59285935
//
@@ -5941,6 +5948,39 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
59415948
}
59425949
}
59435950

5951+
auto anchor = locator.getAnchor();
5952+
5953+
if ((isExpr<UnresolvedDotExpr>(anchor) ||
5954+
isExpr<UnresolvedMemberExpr>(anchor)) &&
5955+
req->is<LocatorPathElt::TypeParameterRequirement>()) {
5956+
auto signature = path[path.size() - 2]
5957+
.castTo<LocatorPathElt::OpenedGeneric>()
5958+
.getSignature();
5959+
auto requirement = signature->getRequirements()[req->getIndex()];
5960+
5961+
auto *memberLoc = getConstraintLocator(anchor, path.front());
5962+
auto *memberRef = findResolvedMemberRef(memberLoc);
5963+
5964+
// To figure out what is going on here we need to wait until
5965+
// member overload is set in the constraint system.
5966+
if (!memberRef)
5967+
return formUnsolved(/*activate=*/true);
5968+
5969+
// If this is a `Self` conformance requirement from a static member
5970+
// reference on a protocol metatype, let's produce a tailored diagnostic.
5971+
if (memberRef->isStatic()) {
5972+
if (auto *protocolDecl =
5973+
memberRef->getDeclContext()->getSelfProtocolDecl()) {
5974+
auto selfTy = protocolDecl->getProtocolSelfType();
5975+
if (selfTy->isEqual(requirement.getFirstType())) {
5976+
auto *fix = AllowInvalidStaticMemberRefOnProtocolMetatype::create(
5977+
*this, memberLoc);
5978+
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
5979+
}
5980+
}
5981+
}
5982+
}
5983+
59445984
if (auto *fix =
59455985
fixRequirementFailure(*this, type, protocolTy, anchor, path)) {
59465986
auto impact = assessRequirementFailureImpact(*this, rawType, locator);
@@ -5953,27 +5993,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
59535993
}
59545994
}
59555995

5956-
if (path.back().is<LocatorPathElt::MemberRefBase>()) {
5957-
path.pop_back();
5958-
5959-
auto *memberLoc = getConstraintLocator(anchor, path);
5960-
if (auto overload = findSelectedOverloadFor(memberLoc)) {
5961-
const auto &choice = overload->choice;
5962-
assert(choice.isDecl());
5963-
5964-
auto *decl = choice.getDecl();
5965-
auto nameRef = choice.getFunctionRefKind() == FunctionRefKind::Compound
5966-
? decl->createNameRef()
5967-
: DeclNameRef(decl->getBaseName());
5968-
5969-
auto *fix = AllowTypeOrInstanceMember::create(
5970-
*this, MetatypeType::get(protocolTy, getASTContext()), decl,
5971-
nameRef, memberLoc);
5972-
5973-
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
5974-
}
5975-
}
5976-
59775996
// If this is an implicit Hashable conformance check generated for each
59785997
// index argument of the keypath subscript component, we could just treat
59795998
// it as though it conforms.
@@ -6833,8 +6852,6 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
68336852
// referred from.
68346853
assert(hasStaticMembers);
68356854

6836-
Type resultTy;
6837-
68386855
// Cannot instantiate a protocol or reference a member on
68396856
// protocol composition type.
68406857
if (isa<ConstructorDecl>(decl) ||
@@ -6844,6 +6861,8 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
68446861
return;
68456862
}
68466863

6864+
Type resultTy;
6865+
68476866
if (isa<AbstractFunctionDecl>(decl)) {
68486867
auto refTy =
68496868
decl->getInterfaceType()->castTo<AnyFunctionType>()->getResult();
@@ -8017,10 +8036,11 @@ ConstraintSystem::simplifyUnresolvedMemberChainBaseConstraint(
80178036
auto *memberLoc =
80188037
getConstraintLocator(baseExpr, ConstraintLocator::UnresolvedMember);
80198038

8020-
auto *memberRef = findResolvedMemberRef(memberLoc);
8021-
assert(memberRef);
8039+
if (shouldAttemptFixes() && hasFixFor(memberLoc))
8040+
return SolutionKind::Solved;
80228041

8023-
if (memberRef->isStatic()) {
8042+
auto *memberRef = findResolvedMemberRef(memberLoc);
8043+
if (memberRef && memberRef->isStatic()) {
80248044
return simplifyConformsToConstraint(
80258045
resultTy, baseTy, ConstraintKind::ConformsTo,
80268046
getConstraintLocator(memberLoc, ConstraintLocator::MemberRefBase),

lib/Sema/ConstraintSystem.cpp

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,15 +1577,21 @@ ConstraintSystem::getTypeOfMemberReference(
15771577
Type baseOpenedTy = baseObjTy;
15781578

15791579
if (isStaticMemberRefOnProtocol) {
1580-
// Member type with Self applied.
1581-
auto refTy = openedType->castTo<FunctionType>()->getResult();
1582-
// If member is a function type, let's use its result type
1583-
// since it could be either a static method or a property
1584-
// which returns a function type.
1585-
if (auto *funcTy = refTy->getAs<FunctionType>())
1586-
baseOpenedTy = funcTy->getResult();
1587-
else
1588-
baseOpenedTy = refTy;
1580+
// In diagnostic mode, let's not try to replace base type
1581+
// if there is already a known issue associated with this
1582+
// reference e.g. it might be incorrect initializer call
1583+
// or result type is invalid.
1584+
if (!(shouldAttemptFixes() && hasFixFor(getConstraintLocator(locator)))) {
1585+
// Member type with Self applied.
1586+
auto refTy = openedType->castTo<FunctionType>()->getResult();
1587+
// If member is a function type, let's use its result type
1588+
// since it could be either a static method or a property
1589+
// which returns a function type.
1590+
if (auto *funcTy = refTy->getAs<FunctionType>())
1591+
baseOpenedTy = funcTy->getResult();
1592+
else
1593+
baseOpenedTy = refTy;
1594+
}
15891595
} else if (baseObjTy->isExistentialType()) {
15901596
auto openedArchetype = OpenedArchetypeType::get(baseObjTy);
15911597
OpenedExistentialTypes.push_back(

0 commit comments

Comments
 (0)