diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index bdee8625948..7b8812c8753 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -6374,6 +6374,32 @@ void Decl::printInherited(ASTPrinter &Printer, const PrintOptions &Opts) const { printer.printInherited(this); } +/// Determine whether this typealias is an inferred typealias "Failure" that +/// would conflict with another entity named failure in the same type. +static bool isConflictingFailureTypeWitness( + const TypeAliasDecl *typealias) { + if (!typealias->isImplicit()) + return false; + + ASTContext &ctx = typealias->getASTContext(); + if (typealias->getName() != ctx.Id_Failure) + return false; + + auto nominal = typealias->getDeclContext()->getSelfNominalTypeDecl(); + if (!nominal) + return false; + + // Look for another entity with the same name. + auto lookupResults = nominal->lookupDirect( + typealias->getName(), typealias->getLoc()); + for (auto found : lookupResults) { + if (found != typealias) + return true; + } + + return false; +} + bool Decl::shouldPrintInContext(const PrintOptions &PO) const { // Skip getters/setters. They are part of the variable or subscript. if (isa(this)) @@ -6413,6 +6439,14 @@ bool Decl::shouldPrintInContext(const PrintOptions &PO) const { return PO.PrintIfConfig; } + // Prior to Swift 6, we shouldn't print the inferred associated type + // witness for AsyncSequence.Failure. It is always determined from the + // AsyncIteratorProtocol witness. + if (auto typealias = dyn_cast(this)) { + if (isConflictingFailureTypeWitness(typealias)) + return false; + } + // Print everything else. return true; } diff --git a/lib/Sema/AssociatedTypeInference.cpp b/lib/Sema/AssociatedTypeInference.cpp index 5ce603d0cec..6f694944a61 100644 --- a/lib/Sema/AssociatedTypeInference.cpp +++ b/lib/Sema/AssociatedTypeInference.cpp @@ -389,6 +389,35 @@ static void recordTypeWitness(NormalProtocolConformance *conformance, } } +/// Determine whether this is the AsyncIteratorProtocol.Failure associated type. +static bool isAsyncIteratorProtocolFailure(AssociatedTypeDecl *assocType) { + auto proto = assocType->getProtocol(); + if (!proto->isSpecificProtocol(KnownProtocolKind::AsyncIteratorProtocol)) + return false; + + return assocType->getName() == assocType->getASTContext().Id_Failure; +} + +/// Determine whether this is the AsyncSequence.Failure associated type. +static bool isAsyncSequenceFailure(AssociatedTypeDecl *assocType) { + auto proto = assocType->getProtocol(); + if (!proto->isSpecificProtocol(KnownProtocolKind::AsyncSequence)) + return false; + + return assocType->getName() == assocType->getASTContext().Id_Failure; +} + +/// Determine whether this is the AsyncIteratorProtocol.Failure or +/// AsyncSequence.Failure associated type. +static bool isAsyncIteratorOrSequenceFailure(AssociatedTypeDecl *assocType) { + auto proto = assocType->getProtocol(); + if (!proto->isSpecificProtocol(KnownProtocolKind::AsyncIteratorProtocol) && + !proto->isSpecificProtocol(KnownProtocolKind::AsyncSequence)) + return false; + + return assocType->getName() == assocType->getASTContext().Id_Failure; +} + /// Attempt to resolve a type witness via member name lookup. static ResolveWitnessResult resolveTypeWitnessViaLookup( NormalProtocolConformance *conformance, @@ -396,6 +425,13 @@ static ResolveWitnessResult resolveTypeWitnessViaLookup( auto *dc = conformance->getDeclContext(); auto &ctx = dc->getASTContext(); + // Prior to Swift 6, don't look for a named type witness for + // AsyncSequence.Failure. We'll always infer it from + // AsyncIteratorProtocol.Failure. + if (isAsyncSequenceFailure(assocType) && + !ctx.LangOpts.isSwiftVersionAtLeast(6)) + return ResolveWitnessResult::Missing; + // Conformances constructed by the ClangImporter should have explicit type // witnesses already. if (isa(dc->getModuleScopeContext())) { @@ -1816,17 +1852,6 @@ next_witness:; return result; } -/// Determine whether this is AsyncIteratorProtocol.Failure or -/// AsyncSequenceProtoco.Failure associated type. -static bool isAsyncIteratorProtocolFailure(AssociatedTypeDecl *assocType) { - auto proto = assocType->getProtocol(); - if (!proto->isSpecificProtocol(KnownProtocolKind::AsyncIteratorProtocol) && - !proto->isSpecificProtocol(KnownProtocolKind::AsyncSequence)) - return false; - - return assocType->getName() == assocType->getASTContext().Id_Failure; -} - /// Determine whether this is AsyncIteratorProtocol.next() function. static bool isAsyncIteratorProtocolNext(ValueDecl *req) { auto proto = dyn_cast(req->getDeclContext()); @@ -1834,7 +1859,8 @@ static bool isAsyncIteratorProtocolNext(ValueDecl *req) { !proto->isSpecificProtocol(KnownProtocolKind::AsyncIteratorProtocol)) return false; - return req->getName().getBaseName() == req->getASTContext().Id_next; + return req->getName().getBaseName() == req->getASTContext().Id_next && + req->getName().getArgumentNames().empty(); } InferredAssociatedTypes @@ -2537,8 +2563,7 @@ std::optional AssociatedTypeInference::computeFailureTypeWitness( AssociatedTypeDecl *assocType, ArrayRef> valueWitnesses) const { - // Inference only applies to AsyncIteratorProtocol.Failure and - // AsyncSequence.Failure. + // Inference only applies to AsyncIteratorProtocol.Failure. if (!isAsyncIteratorProtocolFailure(assocType)) return std::nullopt; @@ -2582,7 +2607,7 @@ AssociatedTypeInference::computeDefaultTypeWitness( AssociatedTypeDecl *assocType) const { // Ignore the default for AsyncIteratorProtocol.Failure and // AsyncSequence.Failure. - if (isAsyncIteratorProtocolFailure(assocType)) + if (isAsyncIteratorOrSequenceFailure(assocType)) return std::nullopt; // Go find a default definition. @@ -2683,8 +2708,8 @@ AssociatedTypeInference::computeAbstractTypeWitness( // Don't consider the generic parameter names for AsyncSequence.Failure or // AsyncIteratorProtocol.Failure; we always rely on inference from next() or - // next(_:). - if (isAsyncIteratorProtocolFailure(assocType)) { + // next(isolation:). + if (isAsyncIteratorOrSequenceFailure(assocType)) { // If this is specifically AsyncSequence.Failure with the older associated // type inference implementation, our abstract witness is // "AsyncIterator.Failure". The new implementation is smart enough to do @@ -2727,7 +2752,7 @@ Type AssociatedTypeInference::computeGenericParamWitness( if (auto genericSig = dc->getGenericSignatureOfContext()) { // Ignore the generic parameters for AsyncIteratorProtocol.Failure and // AsyncSequence.Failure. - if (!isAsyncIteratorProtocolFailure(assocType)) { + if (!isAsyncIteratorOrSequenceFailure(assocType)) { for (auto *gp : genericSig.getInnermostGenericParams()) { // Packs cannot witness associated type requirements. if (gp->isParameterPack()) diff --git a/test/Concurrency/async_sequence_syntax.swift b/test/Concurrency/async_sequence_syntax.swift index a337f3655c7..5478335a9cd 100644 --- a/test/Concurrency/async_sequence_syntax.swift +++ b/test/Concurrency/async_sequence_syntax.swift @@ -99,3 +99,23 @@ func forTryAwaitReturningExistentialType() async throws { for try await _ in S().seq() { // Ok } } + +@available(SwiftStdlib 5.1, *) +public struct ReaderSeq: AsyncSequence, Sendable { + public enum Failure: Error { + case x + } + + public typealias Element = Int + + public func makeAsyncIterator() -> Reader {} + + public actor Reader: AsyncIteratorProtocol { + public func next() async throws -> Element? {} + } +} + +@available(SwiftStdlib 5.1, *) +func test1() -> Error { + return ReaderSeq.Failure.x +} diff --git a/test/ModuleInterface/async_sequence_conformance.swift b/test/ModuleInterface/async_sequence_conformance.swift index 8de164de830..7162c421809 100644 --- a/test/ModuleInterface/async_sequence_conformance.swift +++ b/test/ModuleInterface/async_sequence_conformance.swift @@ -25,3 +25,30 @@ public struct SequenceAdapter: AsyncSequence { // CHECK: @available( // CHECK-NEXT: public typealias Failure = Base.Failure } + +// CHECK: @available( +// CHECK-NEXT: public struct OtherSequenceAdapte +@available(SwiftStdlib 5.1, *) +public struct OtherSequenceAdapter: AsyncSequence { + // CHECK: public typealias Element = Base.Element + // CHECK-NOT: public typealias Failure + // CHECK: public struct Failure + + // CHECK-LABEL: public struct AsyncIterator + // CHECK: @available{{.*}}macOS 10.15 + // CHECK: @available( + // CHECK-NEXT: public typealias Failure = Base.Failure + public typealias Element = Base.Element + + public struct Failure: Error { } + + // CHECK-NOT: public typealias Failure + public struct AsyncIterator: AsyncIteratorProtocol { + public mutating func next() async rethrows -> Base.Element? { nil } + } + + // CHECK: public func makeAsyncIterator + public func makeAsyncIterator() -> AsyncIterator { AsyncIterator() } + + // CHECK-NOT: public typealias Failure +}