Skip to content

Commit 04ed519

Browse files
committed
[Associated type inference] Support @_implements on type witnesses
Extend the longstanding support for `@_implements` on witnesses to also work on type witnesses, as part of associated type inference. This permits an associated type witness to have a different name from the associated type itself.
1 parent 76e71e7 commit 04ed519

File tree

4 files changed

+46
-8
lines changed

4 files changed

+46
-8
lines changed

lib/Sema/AssociatedTypeInference.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,8 @@ static ResolveWitnessResult resolveTypeWitnessViaLookup(
429429
abort();
430430
}
431431

432-
NLOptions subOptions = (NL_QualifiedDefault | NL_OnlyTypes | NL_ProtocolMembers);
432+
NLOptions subOptions = (NL_QualifiedDefault | NL_OnlyTypes |
433+
NL_ProtocolMembers | NL_IncludeAttributeImplements);
433434

434435
// Look for a member type with the same name as the associated type.
435436
SmallVector<ValueDecl *, 4> candidates;
@@ -455,6 +456,16 @@ static ResolveWitnessResult resolveTypeWitnessViaLookup(
455456
if (isa<AssociatedTypeDecl>(typeDecl))
456457
continue;
457458

459+
// If the name doesn't match and there's no appropriate @_implements
460+
// attribute, skip this candidate.
461+
//
462+
// Also skip candidates in protocol extensions, because they tend to cause
463+
// request cycles. We'll look at those during associated type inference.
464+
if (assocType->getName() != typeDecl->getName() &&
465+
!(witnessHasImplementsAttrForRequiredName(typeDecl, assocType) &&
466+
!typeDecl->getDeclContext()->getSelfProtocolDecl()))
467+
continue;
468+
458469
auto *genericDecl = cast<GenericTypeDecl>(typeDecl);
459470

460471
// If the declaration has generic parameters, it cannot witness an
@@ -2039,7 +2050,8 @@ AssociatedTypeInference::inferTypeWitnessesViaAssociatedType(
20392050

20402051
NLOptions subOptions = (NL_QualifiedDefault |
20412052
NL_OnlyTypes |
2042-
NL_ProtocolMembers);
2053+
NL_ProtocolMembers |
2054+
NL_IncludeAttributeImplements);
20432055

20442056
// Look for types with the given default name that have appropriate
20452057
// @_implements attributes.
@@ -2061,6 +2073,12 @@ AssociatedTypeInference::inferTypeWitnessesViaAssociatedType(
20612073
if (!defaultProto)
20622074
continue;
20632075

2076+
// If the name doesn't match and there's no appropriate @_implements
2077+
// attribute, skip this candidate.
2078+
if (defaultName.getBaseName() != typeDecl->getName() &&
2079+
!witnessHasImplementsAttrForRequiredName(typeDecl, assocType))
2080+
continue;
2081+
20642082
// Determine the witness type.
20652083
Type witnessType = getWitnessTypeForMatching(conformance, typeDecl);
20662084
if (!witnessType) continue;

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,18 +1281,18 @@ swift::matchWitness(WitnessChecker::RequirementEnvironmentCache &reqEnvCache,
12811281
return matchWitness(dc, req, witness, setup, matchTypes, finalize);
12821282
}
12831283

1284-
static bool
1285-
witnessHasImplementsAttrForRequiredName(ValueDecl *witness,
1286-
ValueDecl *requirement) {
1284+
bool
1285+
swift::witnessHasImplementsAttrForRequiredName(ValueDecl *witness,
1286+
ValueDecl *requirement) {
12871287
if (auto A = witness->getAttrs().getAttribute<ImplementsAttr>()) {
12881288
return A->getMemberName() == requirement->getName();
12891289
}
12901290
return false;
12911291
}
12921292

1293-
static bool
1294-
witnessHasImplementsAttrForExactRequirement(ValueDecl *witness,
1295-
ValueDecl *requirement) {
1293+
bool
1294+
swift::witnessHasImplementsAttrForExactRequirement(ValueDecl *witness,
1295+
ValueDecl *requirement) {
12961296
assert(requirement->isProtocolRequirement());
12971297
auto *PD = cast<ProtocolDecl>(requirement->getDeclContext());
12981298
if (auto A = witness->getAttrs().getAttribute<ImplementsAttr>()) {

lib/Sema/TypeCheckProtocol.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,16 @@ AssociatedTypeDecl *findDefaultedAssociatedType(
223223
DeclContext *dc, NominalTypeDecl *adoptee,
224224
AssociatedTypeDecl *assocType);
225225

226+
/// Determine whether this witness has an `@_implements` attribute whose
227+
/// name matches that of the given requirement.
228+
bool witnessHasImplementsAttrForRequiredName(ValueDecl *witness,
229+
ValueDecl *requirement);
230+
231+
/// Determine whether this witness has an `@_implements` attribute whose name
232+
/// and protocol match that of the requirement exactly.
233+
bool witnessHasImplementsAttrForExactRequirement(ValueDecl *witness,
234+
ValueDecl *requirement);
235+
226236
}
227237

228238
#endif // SWIFT_SEMA_PROTOCOL_H

test/attr/attr_implements.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,13 @@ func falseWhenSpecificType(_ x: SpecificType) -> Bool { return x == x }
9797

9898
assert(trueWhenJustEquatable(SpecificType()))
9999
assert(!falseWhenSpecificType(SpecificType()))
100+
101+
// @_implements on associated types
102+
protocol PWithAssoc {
103+
associatedtype A
104+
}
105+
106+
struct XWithAssoc: PWithAssoc {
107+
@_implements(PWithAssoc, A)
108+
typealias __P_A = Int
109+
}

0 commit comments

Comments
 (0)