Skip to content

Commit f9c3475

Browse files
committed
Parameterize conformance lookup on whether "missing" conformances are allowed.
Many clients of the conformance lookup operations would prefer to get an invalid conformance (== there is no conformance) rather than a missing conformance. Parameterize the conformance lookup operations so that most callers won't see missing conformances, by filtering them out at the end. Opt-in those callers that do want to see missing conformances so they can be diagnosed.
1 parent de44396 commit f9c3475

13 files changed

+75
-45
lines changed

include/swift/AST/GenericSignature.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,8 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final
373373
/// T: Foo or T == U (etc.) with the information it knows. This includes
374374
/// checking against global state, if any/all of the types in the requirement
375375
/// are concrete, not type parameters.
376-
bool isRequirementSatisfied(Requirement requirement) const;
376+
bool isRequirementSatisfied(
377+
Requirement requirement, bool allowMissing = false) const;
377378

378379
/// Return the requirements of this generic signature that are not also
379380
/// satisfied by \c otherSig.

include/swift/AST/Module.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -578,10 +578,15 @@ class ModuleDecl : public DeclContext, public TypeDecl {
578578
///
579579
/// \param protocol The protocol to which we are computing conformance.
580580
///
581+
/// \param allowMissing When \c true, the resulting conformance reference
582+
/// might include "missing" conformances, which are synthesized for some
583+
/// protocols as an error recovery mechanism.
584+
///
581585
/// \returns The result of the conformance search, which will be
582586
/// None if the type does not conform to the protocol or contain a
583587
/// ProtocolConformanceRef if it does conform.
584-
ProtocolConformanceRef lookupConformance(Type type, ProtocolDecl *protocol);
588+
ProtocolConformanceRef lookupConformance(Type type, ProtocolDecl *protocol,
589+
bool allowMissing = false);
585590

586591
/// Look for the conformance of the given existential type to the given
587592
/// protocol.

include/swift/AST/ProtocolConformanceRef.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ class ProtocolConformanceRef {
9898
return Union.get<ProtocolDecl*>();
9999
}
100100

101+
/// Determine whether this conformance (or a conformance it depends on)
102+
/// involves a "missing" conformance anywhere. Such conformances
103+
/// cannot be depended on to always exist.
104+
bool hasMissingConformance(ModuleDecl *module) const;
105+
101106
using OpaqueValue = void*;
102107
OpaqueValue getOpaqueValue() const { return Union.getOpaqueValue(); }
103108
static ProtocolConformanceRef getFromOpaqueValue(OpaqueValue value) {

include/swift/AST/Requirement.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ class Requirement
8181
/// \param conditionalRequirements An out parameter initialized to an
8282
/// array of requirements that the caller must check to ensure this
8383
/// requirement is completely satisfied.
84-
bool isSatisfied(ArrayRef<Requirement> &conditionalRequirements) const;
84+
bool isSatisfied(ArrayRef<Requirement> &conditionalRequirements,
85+
bool allowMissing = false) const;
8586

8687
/// Determines if this substituted requirement can ever be satisfied,
8788
/// possibly with additional substitutions.

lib/AST/GenericSignature.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -937,7 +937,7 @@ bool GenericSignatureImpl::areSameTypeParameterInContext(Type type1,
937937
}
938938

939939
bool GenericSignatureImpl::isRequirementSatisfied(
940-
Requirement requirement) const {
940+
Requirement requirement, bool allowMissing) const {
941941
if (requirement.getFirstType()->hasTypeParameter()) {
942942
auto *genericEnv = getGenericEnvironment();
943943

@@ -959,7 +959,7 @@ bool GenericSignatureImpl::isRequirementSatisfied(
959959
// FIXME: Need to check conditional requirements here.
960960
ArrayRef<Requirement> conditionalRequirements;
961961

962-
return requirement.isSatisfied(conditionalRequirements);
962+
return requirement.isSatisfied(conditionalRequirements, allowMissing);
963963
}
964964

965965
SmallVector<Requirement, 4> GenericSignatureImpl::requirementsNotSatisfiedBy(
@@ -1391,12 +1391,14 @@ ProtocolDecl *Requirement::getProtocolDecl() const {
13911391
}
13921392

13931393
bool
1394-
Requirement::isSatisfied(ArrayRef<Requirement> &conditionalRequirements) const {
1394+
Requirement::isSatisfied(ArrayRef<Requirement> &conditionalRequirements,
1395+
bool allowMissing) const {
13951396
switch (getKind()) {
13961397
case RequirementKind::Conformance: {
13971398
auto *proto = getProtocolDecl();
13981399
auto *module = proto->getParentModule();
1399-
auto conformance = module->lookupConformance(getFirstType(), proto);
1400+
auto conformance = module->lookupConformance(
1401+
getFirstType(), proto, allowMissing);
14001402
if (!conformance)
14011403
return false;
14021404

lib/AST/Module.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -970,8 +970,14 @@ ModuleDecl::lookupExistentialConformance(Type type, ProtocolDecl *protocol) {
970970
return ProtocolConformanceRef::forInvalid();
971971
}
972972

973+
/// Whether we should create missing conformances to the given protocol.
974+
static bool shouldCreateMissingConformances(ProtocolDecl *proto) {
975+
return proto->isSpecificProtocol(KnownProtocolKind::Sendable);
976+
}
977+
973978
ProtocolConformanceRef ModuleDecl::lookupConformance(Type type,
974-
ProtocolDecl *protocol) {
979+
ProtocolDecl *protocol,
980+
bool allowMissing) {
975981
// If we are recursively checking for implicit conformance of a nominal
976982
// type to Sendable, fail without evaluating this request. This
977983
// squashes cycles.
@@ -985,18 +991,27 @@ ProtocolConformanceRef ModuleDecl::lookupConformance(Type type,
985991
}
986992
}
987993

988-
return evaluateOrDefault(
994+
auto result = evaluateOrDefault(
989995
getASTContext().evaluator, request, ProtocolConformanceRef::forInvalid());
996+
997+
// If we aren't supposed to allow missing conformances through for this
998+
// protocol, replace the result with an "invalid" result.
999+
if (!allowMissing &&
1000+
shouldCreateMissingConformances(protocol) &&
1001+
result.hasMissingConformance(this))
1002+
return ProtocolConformanceRef::forInvalid();
1003+
1004+
return result;
9901005
}
9911006

9921007
/// Retrieve an invalid or missing conformance, as appropriate, when a
9931008
/// legitimate conformance doesn't exist.
9941009
static ProtocolConformanceRef getInvalidOrMissingConformance(
9951010
Type type, ProtocolDecl *proto) {
996-
// Introduce "missing" conformances to Sendable, so that type checking
1011+
// Introduce "missing" conformances when appropriate, so that type checking
9971012
// (and even code generation) can continue.
9981013
ASTContext &ctx = proto->getASTContext();
999-
if (proto->isSpecificProtocol(KnownProtocolKind::Sendable)) {
1014+
if (shouldCreateMissingConformances(proto)) {
10001015
return ProtocolConformanceRef(
10011016
ctx.getBuiltinConformance(
10021017
type, proto, GenericSignature(), { },

lib/AST/ProtocolConformance.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1664,3 +1664,27 @@ SourceLoc swift::extractNearestSourceLoc(const ProtocolConformanceRef conformanc
16641664
}
16651665
return SourceLoc();
16661666
}
1667+
1668+
bool ProtocolConformanceRef::hasMissingConformance(ModuleDecl *module) const {
1669+
if (!isConcrete())
1670+
return false;
1671+
1672+
// Is this a missing Sendable conformance?
1673+
const ProtocolConformance *concreteConf = getConcrete();
1674+
const RootProtocolConformance *rootConf = concreteConf->getRootConformance();
1675+
if (auto builtinConformance = dyn_cast<BuiltinProtocolConformance>(rootConf)){
1676+
if (builtinConformance->isMissing() && builtinConformance->getProtocol()->isSpecificProtocol(
1677+
KnownProtocolKind::Sendable)) {
1678+
return true;
1679+
}
1680+
}
1681+
1682+
// Check conformances that are part of this conformance.
1683+
auto subMap = concreteConf->getSubstitutions(module);
1684+
for (auto conformance : subMap.getConformances()) {
1685+
if (conformance.hasMissingConformance(module))
1686+
return true;
1687+
}
1688+
1689+
return false;
1690+
}

lib/AST/Type.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3772,7 +3772,8 @@ operator()(CanType dependentType, Type conformingReplacementType,
37723772
return ProtocolConformanceRef(conformedProtocol);
37733773

37743774
return M->lookupConformance(conformingReplacementType,
3775-
conformedProtocol);
3775+
conformedProtocol,
3776+
/*allowMissing=*/true);
37763777
}
37773778

37783779
ProtocolConformanceRef LookUpConformanceInSubstitutionMap::

lib/Sema/CSSimplify.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6225,7 +6225,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
62256225
case ConstraintKind::LiteralConformsTo: {
62266226
// Check whether this type conforms to the protocol.
62276227
auto conformance = DC->getParentModule()->lookupConformance(
6228-
type, protocol);
6228+
type, protocol, /*allowMissing=*/true);
62296229
if (conformance) {
62306230
return recordConformance(conformance);
62316231
}

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -546,32 +546,6 @@ static bool isSendableClosure(
546546
return false;
547547
}
548548

549-
/// Look for missing Sendable conformances
550-
static bool hasMissingSendableConformance(
551-
ModuleDecl *module, ProtocolConformanceRef conformance) {
552-
if (!conformance.isConcrete())
553-
return false;
554-
555-
// Is this a missing Sendable conformance?
556-
const ProtocolConformance *concreteConf = conformance.getConcrete();
557-
const RootProtocolConformance *rootConf = concreteConf->getRootConformance();
558-
if (auto builtinConformance = dyn_cast<BuiltinProtocolConformance>(rootConf)){
559-
if (builtinConformance->isMissing() && builtinConformance->getProtocol()->isSpecificProtocol(
560-
KnownProtocolKind::Sendable)) {
561-
return true;
562-
}
563-
}
564-
565-
// Check conformances that are part of this conformance.
566-
auto subMap = concreteConf->getSubstitutions(module);
567-
for (auto conformance : subMap.getConformances()) {
568-
if (hasMissingSendableConformance(module, conformance))
569-
return true;
570-
}
571-
572-
return false;
573-
}
574-
575549
/// Determine whether the given type is suitable as a concurrent value type.
576550
bool swift::isSendableType(ModuleDecl *module, Type type) {
577551
auto proto = module->getASTContext().getProtocol(KnownProtocolKind::Sendable);
@@ -583,7 +557,7 @@ bool swift::isSendableType(ModuleDecl *module, Type type) {
583557
return false;
584558

585559
// Look for missing Sendable conformances.
586-
return !hasMissingSendableConformance(module, conformance);
560+
return !conformance.hasMissingConformance(module);
587561
}
588562

589563
static bool diagnoseNonConcurrentParameter(

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -800,7 +800,7 @@ RequirementCheckResult TypeChecker::checkGenericArguments(
800800
}
801801

802802
ArrayRef<Requirement> conditionalRequirements;
803-
if (req.isSatisfied(conditionalRequirements)) {
803+
if (req.isSatisfied(conditionalRequirements, /*allowMissing=*/true)) {
804804
if (!conditionalRequirements.empty()) {
805805
assert(req.getKind() == RequirementKind::Conformance);
806806

@@ -897,7 +897,7 @@ TypeChecker::checkGenericArguments(ModuleDecl *module,
897897
while (!worklist.empty()) {
898898
auto req = worklist.pop_back_val();
899899
ArrayRef<Requirement> conditionalRequirements;
900-
if (!req.isSatisfied(conditionalRequirements))
900+
if (!req.isSatisfied(conditionalRequirements, /*allowMissing=*/true))
901901
return RequirementCheckResult::Failure;
902902

903903
worklist.append(conditionalRequirements.begin(),

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3248,7 +3248,8 @@ void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType,
32483248
// Find the conformance for this overridden protocol.
32493249
auto overriddenConformance =
32503250
DC->getParentModule()->lookupConformance(Adoptee,
3251-
overridden->getProtocol());
3251+
overridden->getProtocol(),
3252+
/*allowMissing=*/true);
32523253
if (overriddenConformance.isInvalid() ||
32533254
!overriddenConformance.isConcrete())
32543255
continue;
@@ -5180,7 +5181,7 @@ TypeChecker::containsProtocol(Type T, ProtocolDecl *Proto, ModuleDecl *M,
51805181
ProtocolConformanceRef
51815182
TypeChecker::conformsToProtocol(Type T, ProtocolDecl *Proto, ModuleDecl *M) {
51825183
// Look up conformance in the module.
5183-
auto lookupResult = M->lookupConformance(T, Proto);
5184+
auto lookupResult = M->lookupConformance(T, Proto, /*alllowMissing=*/true);
51845185
if (lookupResult.isInvalid()) {
51855186
return ProtocolConformanceRef::forInvalid();
51865187
}

test/SourceKit/CursorInfo/cursor_symbol_graph.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,8 @@ enum MyEnum {
323323
// CHECKFOO: "vendor":
324324
// CHECKFOO: }
325325
// CHECKFOO: },
326-
// CHECKFOO: "relationships": [],
326+
// CHECKFOO: "relationships": [
327+
// CHECKFOO: "target": "s:s8SendableP",
327328
// CHECKFOO: "symbols": [
328329
// CHECKFOO: {
329330
// CHECKFOO: "accessLevel": "internal",

0 commit comments

Comments
 (0)