Skip to content

Commit b944be2

Browse files
committed
Renamed type witnesses for the Async(Sequence|IteratorProtocol) Failure type
The type aliases for inferred type witnesses to the AsyncSequence and AsyncIteratorProtocol's Failure associated type are getting in the way of existing types with the same name. Therefore, when we create these type aliases, given them weird names (e.g., `__AsyncSequence.Failure`) and wire them up with `@_implements(<protocol>, Failure)` so that associated type inference will find them. This is probably a model we should move to in general, because it's odd that we inject new declarations into types that could cause conflicts. However, start by staging it in for just this one associated type where we have source-compatibility concerns, and we can expand it over time. Fixes rdar://124362873.
1 parent 04ed519 commit b944be2

File tree

2 files changed

+44
-15
lines changed

2 files changed

+44
-15
lines changed

lib/Sema/AssociatedTypeInference.cpp

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,17 @@ static bool containsConcreteDependentMemberType(Type ty) {
231231
});
232232
}
233233

234+
/// Determine whether this is the AsyncIteratorProtocol.Failure or
235+
/// AsyncSequence.Failure associated type.
236+
static bool isAsyncIteratorOrSequenceFailure(AssociatedTypeDecl *assocType) {
237+
auto proto = assocType->getProtocol();
238+
if (!proto->isSpecificProtocol(KnownProtocolKind::AsyncIteratorProtocol) &&
239+
!proto->isSpecificProtocol(KnownProtocolKind::AsyncSequence))
240+
return false;
241+
242+
return assocType->getName() == assocType->getASTContext().Id_Failure;
243+
}
244+
234245
static void recordTypeWitness(NormalProtocolConformance *conformance,
235246
AssociatedTypeDecl *assocType,
236247
Type type,
@@ -254,14 +265,40 @@ static void recordTypeWitness(NormalProtocolConformance *conformance,
254265

255266
// If there was no type declaration, synthesize one.
256267
if (typeDecl == nullptr) {
268+
Identifier name;
269+
bool needsImplementsAttr;
270+
if (isAsyncIteratorOrSequenceFailure(assocType)) {
271+
// Use __<protocol>_<assocType> as the name, to keep it out of the
272+
// way of other names.
273+
llvm::SmallString<32> nameBuffer;
274+
nameBuffer += "__";
275+
nameBuffer += assocType->getProtocol()->getName().str();
276+
nameBuffer += "_";
277+
nameBuffer += assocType->getName().str();
278+
279+
name = ctx.getIdentifier(nameBuffer);
280+
needsImplementsAttr = true;
281+
} else {
282+
// Declare a typealias with the same name as the associated type.
283+
name = assocType->getName();
284+
needsImplementsAttr = false;
285+
}
286+
257287
auto aliasDecl = new (ctx) TypeAliasDecl(
258-
SourceLoc(), SourceLoc(), assocType->getName(), SourceLoc(),
288+
SourceLoc(), SourceLoc(), name, SourceLoc(),
259289
/*genericparams*/ nullptr, dc);
260290
aliasDecl->setUnderlyingType(type);
261291

262292
aliasDecl->setImplicit();
263293
aliasDecl->setSynthesized();
264294

295+
// If needed, add an @_implements(Protocol, Name) attribute.
296+
if (needsImplementsAttr) {
297+
auto attr = ImplementsAttr::create(
298+
dc, assocType->getProtocol(), assocType->getName());
299+
aliasDecl->getAttrs().add(attr);
300+
}
301+
265302
// Inject the typealias into the nominal decl that conforms to the protocol.
266303
auto nominal = dc->getSelfNominalTypeDecl();
267304
auto requiredAccessScope = evaluateOrDefault(
@@ -395,17 +432,6 @@ static bool isAsyncSequenceFailure(AssociatedTypeDecl *assocType) {
395432
return assocType->getName() == assocType->getASTContext().Id_Failure;
396433
}
397434

398-
/// Determine whether this is the AsyncIteratorProtocol.Failure or
399-
/// AsyncSequence.Failure associated type.
400-
static bool isAsyncIteratorOrSequenceFailure(AssociatedTypeDecl *assocType) {
401-
auto proto = assocType->getProtocol();
402-
if (!proto->isSpecificProtocol(KnownProtocolKind::AsyncIteratorProtocol) &&
403-
!proto->isSpecificProtocol(KnownProtocolKind::AsyncSequence))
404-
return false;
405-
406-
return assocType->getName() == assocType->getASTContext().Id_Failure;
407-
}
408-
409435
/// Attempt to resolve a type witness via member name lookup.
410436
static ResolveWitnessResult resolveTypeWitnessViaLookup(
411437
NormalProtocolConformance *conformance,

test/ModuleInterface/async_sequence_conformance.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ public struct SequenceAdapter<Base: AsyncSequence>: AsyncSequence {
1212
// CHECK: @available{{.*}}macOS 10.15
1313
// CHECK-NEXT: public typealias Element = Base.Element
1414
// CHECK: @available(
15-
// CHECK-NEXT: public typealias Failure = Base.Failure
15+
// CHECK: @_implements(_Concurrency.AsyncIteratorProtocol, Failure)
16+
// CHECK-SAME: public typealias __AsyncIteratorProtocol_Failure = Base.Failure
1617
public typealias Element = Base.Element
1718

1819
public struct AsyncIterator: AsyncIteratorProtocol {
@@ -23,7 +24,8 @@ public struct SequenceAdapter<Base: AsyncSequence>: AsyncSequence {
2324
public func makeAsyncIterator() -> AsyncIterator { AsyncIterator() }
2425

2526
// CHECK: @available(
26-
// CHECK-NEXT: public typealias Failure = Base.Failure
27+
// CHECK: @_implements(_Concurrency.AsyncSequence, Failure)
28+
// CHECK-SAME: public typealias __AsyncSequence_Failure = Base.Failure
2729
}
2830

2931
// CHECK: @available(
@@ -37,7 +39,8 @@ public struct OtherSequenceAdapter<Base: AsyncSequence>: AsyncSequence {
3739
// CHECK-LABEL: public struct AsyncIterator
3840
// CHECK: @available{{.*}}macOS 10.15
3941
// CHECK: @available(
40-
// CHECK-NEXT: public typealias Failure = Base.Failure
42+
// CHECK: @_implements(_Concurrency.AsyncIteratorProtocol, Failure)
43+
// CHECK-SAME: public typealias __AsyncIteratorProtocol_Failure = Base.Failure
4144
public typealias Element = Base.Element
4245

4346
public struct Failure: Error { }

0 commit comments

Comments
 (0)