Skip to content

Commit 6e05240

Browse files
authored
AsyncSequence and protocol conformance rethrows (#35224)
* Initial draft of async sequences * Adjust AsyncSequence associated type requirements * Add a draft implementation of AsyncSequence and associated functionality * Correct merge damage and rename from GeneratorProtocol to AsyncIteratorProtocol * Add AsyncSequence types to the cmake lists * Add cancellation support * [DRAFT] Implementation of protocol conformance rethrowing * Account for ASTVerifier passes to ensure throwing and by conformance rethrowing verifies appropriately * Remove commented out code * OtherConstructorDeclRefExpr can also be a source of a rethrowing kind function * Re-order the checkApply logic to account for existing throwing calculations better * Extract rethrowing calculation into smaller functions * Allow for closures and protocol conformances to contribute to throwing * Add unit tests for conformance based rethrowing * Restrict rethrowing requirements to only protocols marked with @rethrows * Correct logic for gating of `@rethrows` and adjust the determinates to be based upon throws and not rethrows spelling * Attempt to unify the async sequence features together * Reorder try await to latest syntax * revert back to the inout diagnosis * House mutations in local scope * Revert "House mutations in local scope" This reverts commit d91f1b25b59fff8e4be107c808895ff3f293b394. * Adjust for inout diagnostics and fall back to original mutation strategy * Convert async flag to source locations and add initial try support to for await in syntax * Fix case typo of MinMax.swift * Adjust rethrowing tests to account for changes associated with @rethrows * Allow parsing and diagnostics associated with try applied to for await in syntax * Correct the code-completion for @rethrows * Additional corrections for the code-completion for @rethrows this time for the last in the list * Handle throwing cases of iteration of async sequences * restore building XCTest * First wave of feedback fixes * Rework constraints checking for async sequence for-try-await-in checking * Allow testing of for-await-in parsing and silgen testing and add unit tests for both * Remove async sequence operators for now * Back out cancellation of AsyncIteratorProtocols * Restructure protocol conformance throws checking and cache results * remove some stray whitespaces * Correct some merge damage * Ensure the throwing determinate for applying for-await-in always has a valid value and adjust the for-await-in silgen test to reflect the cancel changes * Squelch the python linter for line length
1 parent a86430b commit 6e05240

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1413
-84
lines changed

include/swift/AST/ASTContext.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,9 @@ class ASTContext final {
522522
/// Get Sequence.makeIterator().
523523
FuncDecl *getSequenceMakeIterator() const;
524524

525+
/// Get AsyncSequence.makeAsyncIterator().
526+
FuncDecl *getAsyncSequenceMakeAsyncIterator() const;
527+
525528
/// Check whether the standard library provides all the correct
526529
/// intrinsic support for Optional<T>.
527530
///

include/swift/AST/ASTTypeIDZone.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ SWIFT_TYPEID(PropertyWrapperTypeInfo)
3131
SWIFT_TYPEID(Requirement)
3232
SWIFT_TYPEID(ResilienceExpansion)
3333
SWIFT_TYPEID(FragileFunctionKind)
34+
SWIFT_TYPEID(FunctionRethrowingKind)
35+
SWIFT_TYPEID(ProtocolRethrowsRequirementList)
3436
SWIFT_TYPEID(TangentPropertyInfo)
3537
SWIFT_TYPEID(SymbolSourceMap)
3638
SWIFT_TYPEID(Type)

include/swift/AST/ASTTypeIDs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ class ProtocolDecl;
6464
class Requirement;
6565
enum class ResilienceExpansion : unsigned;
6666
struct FragileFunctionKind;
67+
enum class FunctionRethrowingKind : uint8_t;
68+
class ProtocolRethrowsRequirementList;
6769
class SourceFile;
6870
class SymbolSourceMap;
6971
struct TangentPropertyInfo;

include/swift/AST/Attr.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,10 @@ SIMPLE_DECL_ATTR(rethrows, Rethrows,
359359
RejectByParser |
360360
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
361361
57)
362+
SIMPLE_DECL_ATTR(rethrows, AtRethrows,
363+
OnProtocol |
364+
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
365+
58)
362366
DECL_ATTR(_swift_native_objc_runtime_base, SwiftNativeObjCRuntimeBase,
363367
OnClass |
364368
UserInaccessible |

include/swift/AST/Decl.h

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3879,6 +3879,66 @@ enum class KnownDerivableProtocolKind : uint8_t {
38793879
Actor,
38803880
};
38813881

3882+
class ProtocolRethrowsRequirementList {
3883+
public:
3884+
typedef std::pair<Type, ValueDecl *> Entry;
3885+
3886+
private:
3887+
ArrayRef<Entry> entries;
3888+
3889+
public:
3890+
ProtocolRethrowsRequirementList(ArrayRef<Entry> entries) : entries(entries) {}
3891+
ProtocolRethrowsRequirementList() : entries() {}
3892+
3893+
typedef const Entry *const_iterator;
3894+
typedef const_iterator iterator;
3895+
3896+
const_iterator begin() const { return entries.begin(); }
3897+
const_iterator end() const { return entries.end(); }
3898+
3899+
size_t size() const { return entries.size(); }
3900+
3901+
void print(raw_ostream &OS) const;
3902+
3903+
SWIFT_DEBUG_DUMP;
3904+
3905+
friend bool operator==(const ProtocolRethrowsRequirementList &lhs,
3906+
const ProtocolRethrowsRequirementList &rhs) {
3907+
if (lhs.size() != rhs.size()) {
3908+
return false;
3909+
}
3910+
auto lhsIter = lhs.begin();
3911+
auto rhsIter = rhs.begin();
3912+
while (lhsIter != lhs.end() && rhsIter != rhs.end()) {
3913+
if (lhsIter->first->isEqual(rhsIter->first)) {
3914+
return false;
3915+
}
3916+
if (lhsIter->second != rhsIter->second) {
3917+
return false;
3918+
}
3919+
}
3920+
return true;
3921+
}
3922+
3923+
friend bool operator!=(const ProtocolRethrowsRequirementList &lhs,
3924+
const ProtocolRethrowsRequirementList &rhs) {
3925+
return !(lhs == rhs);
3926+
}
3927+
3928+
friend llvm::hash_code hash_value(
3929+
const ProtocolRethrowsRequirementList &list) {
3930+
return llvm::hash_combine(list.size()); // it is good enought for
3931+
// llvm::hash_code hash;
3932+
// for (auto entry : list) {
3933+
// hash = llvm::hash_combine(hash, entry.first->getCanonicalType());
3934+
// hash = llvm::hash_combine(hash, entry.second);
3935+
// }
3936+
// return hash;
3937+
}
3938+
};
3939+
3940+
void simple_display(raw_ostream &out, const ProtocolRethrowsRequirementList reqs);
3941+
38823942
/// ProtocolDecl - A declaration of a protocol, for example:
38833943
///
38843944
/// protocol Drawable {
@@ -4060,6 +4120,9 @@ class ProtocolDecl final : public NominalTypeDecl {
40604120
/// contain 'Self' in 'parameter' or 'other' position.
40614121
bool existentialTypeSupported() const;
40624122

4123+
ProtocolRethrowsRequirementList getRethrowingRequirements() const;
4124+
bool isRethrowingProtocol() const;
4125+
40634126
private:
40644127
void computeKnownProtocolKind() const;
40654128

@@ -5469,6 +5532,23 @@ class ImportAsMemberStatus {
54695532
}
54705533
};
54715534

5535+
enum class FunctionRethrowingKind : uint8_t {
5536+
/// The function is not throwing
5537+
None,
5538+
5539+
/// The function rethrows by closure
5540+
ByClosure,
5541+
5542+
/// The function rethrows by conformance
5543+
ByConformance,
5544+
5545+
/// The function throws
5546+
Throws,
5547+
5548+
/// The function throwing determinate is invalid
5549+
Invalid
5550+
};
5551+
54725552
/// Base class for function-like declarations.
54735553
class AbstractFunctionDecl : public GenericContext, public ValueDecl {
54745554
friend class NeedsNewVTableEntryRequest;
@@ -5671,6 +5751,8 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
56715751
/// Returns true if the function body throws.
56725752
bool hasThrows() const { return Bits.AbstractFunctionDecl.Throws; }
56735753

5754+
FunctionRethrowingKind getRethrowingKind() const;
5755+
56745756
// FIXME: Hack that provides names with keyword arguments for accessors.
56755757
DeclName getEffectiveFullName() const;
56765758

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2983,6 +2983,8 @@ ERROR(override_rethrows_with_non_rethrows,none,
29832983
"be 'rethrows'", (bool))
29842984
ERROR(rethrows_without_throwing_parameter,none,
29852985
"'rethrows' function must take a throwing function argument", ())
2986+
ERROR(rethrows_attr_on_non_protocol,none,
2987+
"@rethrows may only be used on 'protocol' declarations", ())
29862988

29872989
ERROR(autoclosure_function_type,none,
29882990
"@autoclosure attribute only applies to function types",
@@ -4059,6 +4061,8 @@ NOTE(because_rethrows_argument_throws,none,
40594061
NOTE(because_rethrows_default_argument_throws,none,
40604062
"call is to 'rethrows' function, but a defaulted argument function"
40614063
" can throw", ())
4064+
NOTE(because_rethrows_default_conformance_throws,none,
4065+
"call is to 'rethrows' function, but a conformance has a throwing witness", ())
40624066

40634067
ERROR(throwing_call_in_nonthrowing_autoclosure,none,
40644068
"call can throw, but it is executed in a non-throwing "

include/swift/AST/KnownIdentifiers.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,9 @@ IDENTIFIER(KeyedEncodingContainer)
9393
IDENTIFIER(keyedBy)
9494
IDENTIFIER(keyPath)
9595
IDENTIFIER(makeIterator)
96+
IDENTIFIER(makeAsyncIterator)
9697
IDENTIFIER(Iterator)
98+
IDENTIFIER(AsyncIterator)
9799
IDENTIFIER(load)
98100
IDENTIFIER(main)
99101
IDENTIFIER_WITH_NAME(MainEntryPoint, "$main")

include/swift/AST/KnownProtocols.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ PROTOCOL(StringInterpolationProtocol)
8888
PROTOCOL(AdditiveArithmetic)
8989
PROTOCOL(Differentiable)
9090

91+
PROTOCOL(AsyncSequence)
92+
PROTOCOL(AsyncIteratorProtocol)
93+
9194
PROTOCOL(FloatingPoint)
9295

9396
EXPRESSIBLE_BY_LITERAL_PROTOCOL(ExpressibleByArrayLiteral, "Array", false)

include/swift/AST/ProtocolConformanceRef.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,13 @@ class ProtocolConformanceRef {
170170
/// Get any additional requirements that are required for this conformance to
171171
/// be satisfied.
172172
ArrayRef<Requirement> getConditionalRequirements() const;
173+
174+
bool classifyAsThrows() const;
173175
};
174176

177+
void simple_display(llvm::raw_ostream &out, ProtocolConformanceRef conformanceRef);
178+
SourceLoc extractNearestSourceLoc(const ProtocolConformanceRef conformanceRef);
179+
175180
} // end namespace swift
176181

177182
#endif // LLVM_SWIFT_AST_PROTOCOLCONFORMANCEREF_H

include/swift/AST/Stmt.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,8 @@ class RepeatWhileStmt : public LabeledStmt {
726726
/// \endcode
727727
class ForEachStmt : public LabeledStmt {
728728
SourceLoc ForLoc;
729+
SourceLoc TryLoc;
730+
SourceLoc AwaitLoc;
729731
Pattern *Pat;
730732
SourceLoc InLoc;
731733
Expr *Sequence;
@@ -741,12 +743,12 @@ class ForEachStmt : public LabeledStmt {
741743
Expr *convertElementExpr = nullptr;
742744

743745
public:
744-
ForEachStmt(LabeledStmtInfo LabelInfo, SourceLoc ForLoc, Pattern *Pat,
745-
SourceLoc InLoc, Expr *Sequence, SourceLoc WhereLoc,
746+
ForEachStmt(LabeledStmtInfo LabelInfo, SourceLoc ForLoc, SourceLoc TryLoc, SourceLoc AwaitLoc,
747+
Pattern *Pat, SourceLoc InLoc, Expr *Sequence, SourceLoc WhereLoc,
746748
Expr *WhereExpr, BraceStmt *Body, Optional<bool> implicit = None)
747749
: LabeledStmt(StmtKind::ForEach, getDefaultImplicitFlag(implicit, ForLoc),
748750
LabelInfo),
749-
ForLoc(ForLoc), Pat(nullptr), InLoc(InLoc), Sequence(Sequence),
751+
ForLoc(ForLoc), TryLoc(TryLoc), AwaitLoc(AwaitLoc), Pat(nullptr), InLoc(InLoc), Sequence(Sequence),
750752
WhereLoc(WhereLoc), WhereExpr(WhereExpr), Body(Body) {
751753
setPattern(Pat);
752754
}
@@ -778,6 +780,9 @@ class ForEachStmt : public LabeledStmt {
778780

779781
/// getWhereLoc - Retrieve the location of the 'where' keyword.
780782
SourceLoc getWhereLoc() const { return WhereLoc; }
783+
784+
SourceLoc getAwaitLoc() const { return AwaitLoc; }
785+
SourceLoc getTryLoc() const { return TryLoc; }
781786

782787
/// getPattern - Retrieve the pattern describing the iteration variables.
783788
/// These variables will only be visible within the body of the loop.

include/swift/AST/TypeCheckRequests.h

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,44 @@ class ExistentialTypeSupportedRequest :
311311
void cacheResult(bool value) const;
312312
};
313313

314+
class ProtocolRethrowsRequirementsRequest :
315+
public SimpleRequest<ProtocolRethrowsRequirementsRequest,
316+
ProtocolRethrowsRequirementList(ProtocolDecl *),
317+
RequestFlags::Cached> {
318+
public:
319+
using SimpleRequest::SimpleRequest;
320+
321+
private:
322+
friend SimpleRequest;
323+
324+
// Evaluation.
325+
ProtocolRethrowsRequirementList
326+
evaluate(Evaluator &evaluator, ProtocolDecl *decl) const;
327+
328+
public:
329+
// Caching.
330+
bool isCached() const { return true; }
331+
};
332+
333+
class ProtocolConformanceRefClassifyAsThrowsRequest :
334+
public SimpleRequest<ProtocolConformanceRefClassifyAsThrowsRequest,
335+
bool(ProtocolConformanceRef),
336+
RequestFlags::Cached> {
337+
public:
338+
using SimpleRequest::SimpleRequest;
339+
340+
private:
341+
friend SimpleRequest;
342+
343+
// Evaluation.
344+
bool
345+
evaluate(Evaluator &evaluator, ProtocolConformanceRef conformanceRef) const;
346+
347+
public:
348+
// Caching.
349+
bool isCached() const { return true; }
350+
};
351+
314352
/// Determine whether the given declaration is 'final'.
315353
class IsFinalRequest :
316354
public SimpleRequest<IsFinalRequest,
@@ -734,6 +772,26 @@ void simple_display(llvm::raw_ostream &out, FragileFunctionKind value);
734772

735773
void simple_display(llvm::raw_ostream &out, ResilienceExpansion value);
736774

775+
class FunctionRethrowingKindRequest :
776+
public SimpleRequest<FunctionRethrowingKindRequest,
777+
FunctionRethrowingKind(AbstractFunctionDecl*),
778+
RequestFlags::Cached> {
779+
public:
780+
using SimpleRequest::SimpleRequest;
781+
782+
private:
783+
friend SimpleRequest;
784+
785+
// Evaluation.
786+
FunctionRethrowingKind evaluate(Evaluator &evaluator, AbstractFunctionDecl *decl) const;
787+
788+
public:
789+
// Caching.
790+
bool isCached() const { return true; }
791+
};
792+
793+
void simple_display(llvm::raw_ostream &out, FunctionRethrowingKind value);
794+
737795
/// Request the custom attribute which attaches a result builder to the
738796
/// given declaration.
739797
class AttachedResultBuilderRequest :

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,8 @@ SWIFT_REQUEST(TypeChecker, RequiresOpaqueModifyCoroutineRequest,
211211
bool(AbstractStorageDecl *), SeparatelyCached, NoLocationInfo)
212212
SWIFT_REQUEST(TypeChecker, FragileFunctionKindRequest,
213213
FragileFunctionKind(DeclContext *), Cached, NoLocationInfo)
214+
SWIFT_REQUEST(TypeChecker, FunctionRethrowingKindRequest,
215+
FunctionRethrowingKind(AbstractFunctionDecl *), Cached, NoLocationInfo)
214216
SWIFT_REQUEST(TypeChecker, SelfAccessKindRequest, SelfAccessKind(FuncDecl *),
215217
SeparatelyCached, NoLocationInfo)
216218
SWIFT_REQUEST(TypeChecker, StorageImplInfoRequest,
@@ -265,6 +267,12 @@ SWIFT_REQUEST(TypeChecker, ResolveImplicitMemberRequest,
265267
SWIFT_REQUEST(TypeChecker, ResolveTypeEraserTypeRequest,
266268
Type(ProtocolDecl *, TypeEraserAttr *),
267269
SeparatelyCached, NoLocationInfo)
270+
SWIFT_REQUEST(TypeChecker, ProtocolRethrowsRequirementsRequest,
271+
ProtocolRethrowsRequirementList(ProtocolDecl *),
272+
Cached, NoLocationInfo)
273+
SWIFT_REQUEST(TypeChecker, ProtocolConformanceRefClassifyAsThrowsRequest,
274+
bool(ProtocolConformanceRef),
275+
Cached, NoLocationInfo)
268276
SWIFT_REQUEST(TypeChecker, ResolveTypeRequest,
269277
Type (const TypeResolution *, TypeRepr *, GenericParamList *),
270278
Uncached, NoLocationInfo)

lib/AST/ASTContext.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@ struct ASTContext::Implementation {
206206
/// The declaration of 'Sequence.makeIterator()'.
207207
FuncDecl *MakeIterator = nullptr;
208208

209+
/// The declaration of 'AsyncSequence.makeAsyncIterator()'.
210+
FuncDecl *MakeAsyncIterator = nullptr;
211+
209212
/// The declaration of Swift.Optional<T>.Some.
210213
EnumElementDecl *OptionalSomeDecl = nullptr;
211214

@@ -772,6 +775,31 @@ FuncDecl *ASTContext::getSequenceMakeIterator() const {
772775
return nullptr;
773776
}
774777

778+
FuncDecl *ASTContext::getAsyncSequenceMakeAsyncIterator() const {
779+
if (getImpl().MakeAsyncIterator) {
780+
return getImpl().MakeAsyncIterator;
781+
}
782+
783+
auto proto = getProtocol(KnownProtocolKind::AsyncSequence);
784+
if (!proto)
785+
return nullptr;
786+
787+
for (auto result : proto->lookupDirect(Id_makeAsyncIterator)) {
788+
if (result->getDeclContext() != proto)
789+
continue;
790+
791+
if (auto func = dyn_cast<FuncDecl>(result)) {
792+
if (func->getParameters()->size() != 0)
793+
continue;
794+
795+
getImpl().MakeAsyncIterator = func;
796+
return func;
797+
}
798+
}
799+
800+
return nullptr;
801+
}
802+
775803
#define KNOWN_STDLIB_TYPE_DECL(NAME, DECL_CLASS, NUM_GENERIC_PARAMS) \
776804
DECL_CLASS *ASTContext::get##NAME##Decl() const { \
777805
if (getImpl().NAME##Decl) \
@@ -943,6 +971,8 @@ ProtocolDecl *ASTContext::getProtocol(KnownProtocolKind kind) const {
943971
M = getLoadedModule(Id_Differentiation);
944972
break;
945973
case KnownProtocolKind::Actor:
974+
case KnownProtocolKind::AsyncSequence:
975+
case KnownProtocolKind::AsyncIteratorProtocol:
946976
M = getLoadedModule(Id_Concurrency);
947977
break;
948978
default:

0 commit comments

Comments
 (0)