Skip to content

Commit f7b0b72

Browse files
committed
Sema: Refactor TypeChecker::containsProtocol() a bit
1 parent efbeaea commit f7b0b72

File tree

3 files changed

+45
-46
lines changed

3 files changed

+45
-46
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8747,11 +8747,12 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
87478747
// separately.
87488748
switch (kind) {
87498749
case ConstraintKind::Subtype: {
8750-
auto conformance = TypeChecker::containsProtocol(
8750+
auto pair = TypeChecker::containsProtocol(
87518751
type, protocol, /*allowMissing=*/true);
8752-
if (conformance) {
8753-
return recordConformance(conformance);
8754-
}
8752+
if (pair.first)
8753+
return SolutionKind::Solved;
8754+
if (pair.second)
8755+
return recordConformance(pair.second);
87558756
} break;
87568757
case ConstraintKind::NonisolatedConformsTo:
87578758
case ConstraintKind::ConformsTo:

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5551,23 +5551,24 @@ void swift::diagnoseConformanceFailure(Type T,
55515551

55525552
// If we're checking conformance of an existential type to a protocol,
55535553
// do a little bit of extra work to produce a better diagnostic.
5554-
if (T->isExistentialType() &&
5555-
TypeChecker::containsProtocol(T, Proto)) {
5556-
5557-
if (!T->isObjCExistentialType()) {
5558-
Type constraintType = T;
5559-
if (auto existential = T->getAs<ExistentialType>())
5560-
constraintType = existential->getConstraintType();
5561-
diags.diagnose(ComplainLoc, diag::type_cannot_conform,
5554+
if (T->isExistentialType()) {
5555+
auto pair = TypeChecker::containsProtocol(T, Proto);
5556+
if (pair.first || pair.second) {
5557+
if (!T->isObjCExistentialType()) {
5558+
Type constraintType = T;
5559+
if (auto existential = T->getAs<ExistentialType>())
5560+
constraintType = existential->getConstraintType();
5561+
diags.diagnose(ComplainLoc, diag::type_cannot_conform,
5562+
T, Proto->getDeclaredInterfaceType());
5563+
diags.diagnose(ComplainLoc,
5564+
diag::only_concrete_types_conform_to_protocols);
5565+
return;
5566+
}
5567+
5568+
diags.diagnose(ComplainLoc, diag::protocol_does_not_conform_static,
55625569
T, Proto->getDeclaredInterfaceType());
5563-
diags.diagnose(ComplainLoc,
5564-
diag::only_concrete_types_conform_to_protocols);
55655570
return;
55665571
}
5567-
5568-
diags.diagnose(ComplainLoc, diag::protocol_does_not_conform_static,
5569-
T, Proto->getDeclaredInterfaceType());
5570-
return;
55715572
}
55725573

55735574
// Special case: diagnose conversion to ExpressibleByNilLiteral, since we
@@ -5685,7 +5686,7 @@ void swift::diagnoseConformanceFailure(Type T,
56855686
T, Proto->getDeclaredInterfaceType());
56865687
}
56875688

5688-
ProtocolConformanceRef
5689+
std::pair<bool, ProtocolConformanceRef>
56895690
TypeChecker::containsProtocol(Type T, ProtocolDecl *Proto,
56905691
bool allowMissing) {
56915692
// Existential types don't need to conform, i.e., they only need to
@@ -5699,7 +5700,8 @@ TypeChecker::containsProtocol(Type T, ProtocolDecl *Proto,
56995700
if (constraint->isEqual(Proto->getDeclaredInterfaceType()) &&
57005701
Proto->requiresSelfConformanceWitnessTable()) {
57015702
auto &ctx = T->getASTContext();
5702-
return ProtocolConformanceRef(ctx.getSelfConformance(Proto));
5703+
auto conformance = ProtocolConformanceRef(ctx.getSelfConformance(Proto));
5704+
return std::make_pair(false, conformance);
57035705
}
57045706

57055707
auto layout = T->getExistentialLayout();
@@ -5711,35 +5713,28 @@ TypeChecker::containsProtocol(Type T, ProtocolDecl *Proto,
57115713
// would result in a missing conformance if type is `& Sendable`
57125714
// protocol composition. It's handled for type as a whole below.
57135715
if (auto superclass = layout.getSuperclass()) {
5714-
auto result =lookupConformance(superclass, Proto,
5715-
/*allowMissing=*/false);
5716-
if (result) {
5717-
return result;
5718-
}
5716+
auto conformance = lookupConformance(superclass, Proto,
5717+
/*allowMissing=*/false);
5718+
if (conformance)
5719+
return std::make_pair(false, conformance);
57195720
}
57205721

57215722
// Next, check if the existential contains the protocol in question.
57225723
for (auto *PD : layout.getProtocols()) {
5723-
// If we found the protocol we're looking for, return an abstract
5724-
// conformance to it.
5725-
if (PD == Proto) {
5726-
// FIXME: Passing an empty Type() here temporarily.
5727-
return ProtocolConformanceRef::forAbstract(Type(), Proto);
5728-
}
5729-
5730-
// Now check refined protocols.
5731-
if (PD->inheritsFrom(Proto)) {
5732-
// FIXME: Passing an empty Type() here temporarily.
5733-
return ProtocolConformanceRef::forAbstract(Type(), Proto);
5734-
}
5724+
// If we found the protocol we're looking for, return the special value.
5725+
if (PD == Proto || PD->inheritsFrom(Proto))
5726+
return std::make_pair(true, ProtocolConformanceRef::forInvalid());
57355727
}
57365728

5737-
return allowMissing ? ProtocolConformanceRef::forMissingOrInvalid(T, Proto)
5738-
: ProtocolConformanceRef::forInvalid();
5729+
auto conformance =
5730+
(allowMissing ? ProtocolConformanceRef::forMissingOrInvalid(T, Proto)
5731+
: ProtocolConformanceRef::forInvalid());
5732+
return std::make_pair(false, conformance);
57395733
}
57405734

57415735
// For non-existential types, this is equivalent to checking conformance.
5742-
return lookupConformance(T, Proto, allowMissing);
5736+
auto conformance = lookupConformance(T, Proto, allowMissing);
5737+
return std::make_pair(false, conformance);
57435738
}
57445739

57455740
bool TypeChecker::conformsToKnownProtocol(

lib/Sema/TypeChecker.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -834,12 +834,15 @@ Expr *addImplicitLoadExpr(
834834
std::function<void(Expr *, Type)> setType =
835835
[](Expr *E, Type type) { E->setType(type); });
836836

837-
/// Determine whether the given type contains the given protocol.
838-
///
839-
/// \returns the conformance, if \c T conforms to the protocol \c Proto, or
840-
/// an empty optional.
841-
ProtocolConformanceRef containsProtocol(Type T, ProtocolDecl *Proto,
842-
bool allowMissing=false);
837+
/// Determine whether the given type either conforms to, or itself an
838+
/// existential subtype of, the given protocol.
839+
///
840+
/// \returns if the first element of the pair is true, T is an existential
841+
/// subtype of Proto, and the second element is ignored; if the first element
842+
/// is false, the second element is the result of the conformance lookup.
843+
std::pair<bool, ProtocolConformanceRef>
844+
containsProtocol(Type T, ProtocolDecl *Proto,
845+
bool allowMissing=false);
843846

844847
/// Check whether the type conforms to a given known protocol.
845848
bool conformsToKnownProtocol(Type type, KnownProtocolKind protocol,

0 commit comments

Comments
 (0)