Skip to content

AsyncSequence and protocol conformance rethrows #35224

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 40 commits into from
Jan 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
1b7e579
Initial draft of async sequences
phausler Sep 18, 2020
a23038a
Adjust AsyncSequence associated type requirements
phausler Sep 18, 2020
ea8d396
Add a draft implementation of AsyncSequence and associated functionality
phausler Dec 9, 2020
db778e7
Correct merge damage and rename from GeneratorProtocol to AsyncIterat…
phausler Dec 9, 2020
9096c48
Add AsyncSequence types to the cmake lists
phausler Dec 10, 2020
ae676a8
Add cancellation support
phausler Dec 17, 2020
faa1da7
[DRAFT] Implementation of protocol conformance rethrowing
phausler Dec 4, 2020
df70e94
Account for ASTVerifier passes to ensure throwing and by conformance …
phausler Dec 6, 2020
d8cef33
Remove commented out code
phausler Dec 7, 2020
0bf5969
OtherConstructorDeclRefExpr can also be a source of a rethrowing kind…
phausler Dec 7, 2020
f3f7b4f
Re-order the checkApply logic to account for existing throwing calcul…
phausler Dec 7, 2020
c0b9d39
Extract rethrowing calculation into smaller functions
phausler Dec 8, 2020
de8ddbe
Allow for closures and protocol conformances to contribute to throwing
phausler Dec 8, 2020
8e5b1dd
Add unit tests for conformance based rethrowing
phausler Dec 8, 2020
92229b6
Restrict rethrowing requirements to only protocols marked with @rethrows
phausler Dec 8, 2020
e8c4cd0
Correct logic for gating of `@rethrows` and adjust the determinates t…
phausler Dec 16, 2020
019d8ad
Attempt to unify the async sequence features together
phausler Dec 24, 2020
10feb16
Reorder try await to latest syntax
phausler Jan 6, 2021
d0f2e06
revert back to the inout diagnosis
phausler Jan 6, 2021
3faaf3c
House mutations in local scope
phausler Jan 7, 2021
2c8e6b1
Revert "House mutations in local scope"
phausler Jan 7, 2021
51fec5b
Adjust for inout diagnostics and fall back to original mutation strategy
phausler Jan 11, 2021
d682168
Convert async flag to source locations and add initial try support to…
phausler Jan 12, 2021
7431ec4
Fix case typo of MinMax.swift
phausler Jan 12, 2021
8aa204b
Adjust rethrowing tests to account for changes associated with @rethrows
phausler Jan 13, 2021
307630f
Allow parsing and diagnostics associated with try applied to for awai…
phausler Jan 13, 2021
0763e2d
Correct the code-completion for @rethrows
phausler Jan 14, 2021
0d940e7
Additional corrections for the code-completion for @rethrows this tim…
phausler Jan 14, 2021
6a640a2
Handle throwing cases of iteration of async sequences
phausler Jan 14, 2021
0f2422d
restore building XCTest
phausler Jan 15, 2021
ac18c22
First wave of feedback fixes
phausler Jan 19, 2021
21ce9b7
Rework constraints checking for async sequence for-try-await-in checking
phausler Jan 20, 2021
48d4bb5
Allow testing of for-await-in parsing and silgen testing and add unit…
phausler Jan 20, 2021
a0f6236
Remove async sequence operators for now
phausler Jan 20, 2021
d4d9249
Back out cancellation of AsyncIteratorProtocols
phausler Jan 20, 2021
b25ccab
Restructure protocol conformance throws checking and cache results
phausler Jan 20, 2021
1821182
remove some stray whitespaces
phausler Jan 20, 2021
b186a7d
Correct some merge damage
phausler Jan 20, 2021
e07ad11
Ensure the throwing determinate for applying for-await-in always has …
phausler Jan 22, 2021
dafe88e
Squelch the python linter for line length
phausler Jan 25, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,9 @@ class ASTContext final {
/// Get Sequence.makeIterator().
FuncDecl *getSequenceMakeIterator() const;

/// Get AsyncSequence.makeAsyncIterator().
FuncDecl *getAsyncSequenceMakeAsyncIterator() const;

/// Check whether the standard library provides all the correct
/// intrinsic support for Optional<T>.
///
Expand Down
2 changes: 2 additions & 0 deletions include/swift/AST/ASTTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ SWIFT_TYPEID(PropertyWrapperTypeInfo)
SWIFT_TYPEID(Requirement)
SWIFT_TYPEID(ResilienceExpansion)
SWIFT_TYPEID(FragileFunctionKind)
SWIFT_TYPEID(FunctionRethrowingKind)
SWIFT_TYPEID(ProtocolRethrowsRequirementList)
SWIFT_TYPEID(TangentPropertyInfo)
SWIFT_TYPEID(SymbolSourceMap)
SWIFT_TYPEID(Type)
Expand Down
2 changes: 2 additions & 0 deletions include/swift/AST/ASTTypeIDs.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ class ProtocolDecl;
class Requirement;
enum class ResilienceExpansion : unsigned;
struct FragileFunctionKind;
enum class FunctionRethrowingKind : uint8_t;
class ProtocolRethrowsRequirementList;
class SourceFile;
class SymbolSourceMap;
struct TangentPropertyInfo;
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/Attr.def
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,10 @@ SIMPLE_DECL_ATTR(rethrows, Rethrows,
RejectByParser |
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
57)
SIMPLE_DECL_ATTR(rethrows, AtRethrows,
OnProtocol |
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's API-stable to remove, is it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm good point, yea this is not API stable to remove.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm so the previous annotation btw marks regular rethrows API stable to remove, isn't that wrong?

58)
DECL_ATTR(_swift_native_objc_runtime_base, SwiftNativeObjCRuntimeBase,
OnClass |
UserInaccessible |
Expand Down
82 changes: 82 additions & 0 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -3870,6 +3870,66 @@ enum class KnownDerivableProtocolKind : uint8_t {
Actor,
};

class ProtocolRethrowsRequirementList {
public:
typedef std::pair<Type, ValueDecl *> Entry;

private:
ArrayRef<Entry> entries;

public:
ProtocolRethrowsRequirementList(ArrayRef<Entry> entries) : entries(entries) {}
ProtocolRethrowsRequirementList() : entries() {}

typedef const Entry *const_iterator;
typedef const_iterator iterator;

const_iterator begin() const { return entries.begin(); }
const_iterator end() const { return entries.end(); }

size_t size() const { return entries.size(); }

void print(raw_ostream &OS) const;

SWIFT_DEBUG_DUMP;

friend bool operator==(const ProtocolRethrowsRequirementList &lhs,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I landed some changes that mean request results no longer have to overload == or hash_value(), so you can remove these if you want

const ProtocolRethrowsRequirementList &rhs) {
if (lhs.size() != rhs.size()) {
return false;
}
auto lhsIter = lhs.begin();
auto rhsIter = rhs.begin();
while (lhsIter != lhs.end() && rhsIter != rhs.end()) {
if (lhsIter->first->isEqual(rhsIter->first)) {
return false;
}
if (lhsIter->second != rhsIter->second) {
return false;
}
}
return true;
}

friend bool operator!=(const ProtocolRethrowsRequirementList &lhs,
const ProtocolRethrowsRequirementList &rhs) {
return !(lhs == rhs);
}

friend llvm::hash_code hash_value(
const ProtocolRethrowsRequirementList &list) {
return llvm::hash_combine(list.size()); // it is good enought for
// llvm::hash_code hash;
// for (auto entry : list) {
// hash = llvm::hash_combine(hash, entry.first->getCanonicalType());
// hash = llvm::hash_combine(hash, entry.second);
// }
// return hash;
}
};

void simple_display(raw_ostream &out, const ProtocolRethrowsRequirementList reqs);

/// ProtocolDecl - A declaration of a protocol, for example:
///
/// protocol Drawable {
Expand Down Expand Up @@ -4051,6 +4111,9 @@ class ProtocolDecl final : public NominalTypeDecl {
/// contain 'Self' in 'parameter' or 'other' position.
bool existentialTypeSupported() const;

ProtocolRethrowsRequirementList getRethrowingRequirements() const;
bool isRethrowingProtocol() const;

private:
void computeKnownProtocolKind() const;

Expand Down Expand Up @@ -5460,6 +5523,23 @@ class ImportAsMemberStatus {
}
};

enum class FunctionRethrowingKind : uint8_t {
/// The function is not throwing
None,

/// The function rethrows by closure
ByClosure,

/// The function rethrows by conformance
ByConformance,

/// The function throws
Throws,

/// The function throwing determinate is invalid
Invalid
};

/// Base class for function-like declarations.
class AbstractFunctionDecl : public GenericContext, public ValueDecl {
friend class NeedsNewVTableEntryRequest;
Expand Down Expand Up @@ -5663,6 +5743,8 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
/// Returns true if the function body throws.
bool hasThrows() const { return Bits.AbstractFunctionDecl.Throws; }

FunctionRethrowingKind getRethrowingKind() const;

// FIXME: Hack that provides names with keyword arguments for accessors.
DeclName getEffectiveFullName() const;

Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -2981,6 +2981,8 @@ ERROR(override_rethrows_with_non_rethrows,none,
"be 'rethrows'", (bool))
ERROR(rethrows_without_throwing_parameter,none,
"'rethrows' function must take a throwing function argument", ())
ERROR(rethrows_attr_on_non_protocol,none,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be necessary because you annotated the attribute with OnProtocol in Attrs.def

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so that means the other code:

void AttributeChecker::visitAtRethrowsAttr(AtRethrowsAttr *attr) {
  if (isa<ProtocolDecl>(D)) {
    return;
  }

  diagnose(attr->getLocation(), diag::rethrows_attr_on_non_protocol);
  attr->setInvalid();
}

should change to this?

void AttributeChecker::visitAtRethrowsAttr(AtRethrowsAttr *attr) { }

"@rethrows may only be used on 'protocol' declarations", ())

ERROR(autoclosure_function_type,none,
"@autoclosure attribute only applies to function types",
Expand Down Expand Up @@ -4052,6 +4054,8 @@ NOTE(because_rethrows_argument_throws,none,
NOTE(because_rethrows_default_argument_throws,none,
"call is to 'rethrows' function, but a defaulted argument function"
" can throw", ())
NOTE(because_rethrows_default_conformance_throws,none,
"call is to 'rethrows' function, but a conformance has a throwing witness", ())

ERROR(throwing_call_in_nonthrowing_autoclosure,none,
"call can throw, but it is executed in a non-throwing "
Expand Down
2 changes: 2 additions & 0 deletions include/swift/AST/KnownIdentifiers.def
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@ IDENTIFIER(KeyedEncodingContainer)
IDENTIFIER(keyedBy)
IDENTIFIER(keyPath)
IDENTIFIER(makeIterator)
IDENTIFIER(makeAsyncIterator)
IDENTIFIER(Iterator)
IDENTIFIER(AsyncIterator)
IDENTIFIER(load)
IDENTIFIER(main)
IDENTIFIER_WITH_NAME(MainEntryPoint, "$main")
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/KnownProtocols.def
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ PROTOCOL(StringInterpolationProtocol)
PROTOCOL(AdditiveArithmetic)
PROTOCOL(Differentiable)

PROTOCOL(AsyncSequence)
PROTOCOL(AsyncIteratorProtocol)

PROTOCOL(FloatingPoint)

EXPRESSIBLE_BY_LITERAL_PROTOCOL(ExpressibleByArrayLiteral, "Array", false)
Expand Down
5 changes: 5 additions & 0 deletions include/swift/AST/ProtocolConformanceRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,13 @@ class ProtocolConformanceRef {
/// Get any additional requirements that are required for this conformance to
/// be satisfied.
ArrayRef<Requirement> getConditionalRequirements() const;

bool classifyAsThrows() const;
};

void simple_display(llvm::raw_ostream &out, ProtocolConformanceRef conformanceRef);
SourceLoc extractNearestSourceLoc(const ProtocolConformanceRef conformanceRef);

} // end namespace swift

#endif // LLVM_SWIFT_AST_PROTOCOLCONFORMANCEREF_H
11 changes: 8 additions & 3 deletions include/swift/AST/Stmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,8 @@ class RepeatWhileStmt : public LabeledStmt {
/// \endcode
class ForEachStmt : public LabeledStmt {
SourceLoc ForLoc;
SourceLoc TryLoc;
SourceLoc AwaitLoc;
Pattern *Pat;
SourceLoc InLoc;
Expr *Sequence;
Expand All @@ -741,12 +743,12 @@ class ForEachStmt : public LabeledStmt {
Expr *convertElementExpr = nullptr;

public:
ForEachStmt(LabeledStmtInfo LabelInfo, SourceLoc ForLoc, Pattern *Pat,
SourceLoc InLoc, Expr *Sequence, SourceLoc WhereLoc,
ForEachStmt(LabeledStmtInfo LabelInfo, SourceLoc ForLoc, SourceLoc TryLoc, SourceLoc AwaitLoc,
Pattern *Pat, SourceLoc InLoc, Expr *Sequence, SourceLoc WhereLoc,
Expr *WhereExpr, BraceStmt *Body, Optional<bool> implicit = None)
: LabeledStmt(StmtKind::ForEach, getDefaultImplicitFlag(implicit, ForLoc),
LabelInfo),
ForLoc(ForLoc), Pat(nullptr), InLoc(InLoc), Sequence(Sequence),
ForLoc(ForLoc), TryLoc(TryLoc), AwaitLoc(AwaitLoc), Pat(nullptr), InLoc(InLoc), Sequence(Sequence),
WhereLoc(WhereLoc), WhereExpr(WhereExpr), Body(Body) {
setPattern(Pat);
}
Expand Down Expand Up @@ -778,6 +780,9 @@ class ForEachStmt : public LabeledStmt {

/// getWhereLoc - Retrieve the location of the 'where' keyword.
SourceLoc getWhereLoc() const { return WhereLoc; }

SourceLoc getAwaitLoc() const { return AwaitLoc; }
SourceLoc getTryLoc() const { return TryLoc; }

/// getPattern - Retrieve the pattern describing the iteration variables.
/// These variables will only be visible within the body of the loop.
Expand Down
58 changes: 58 additions & 0 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,44 @@ class ExistentialTypeSupportedRequest :
void cacheResult(bool value) const;
};

class ProtocolRethrowsRequirementsRequest :
public SimpleRequest<ProtocolRethrowsRequirementsRequest,
ProtocolRethrowsRequirementList(ProtocolDecl *),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

// Evaluation.
ProtocolRethrowsRequirementList
evaluate(Evaluator &evaluator, ProtocolDecl *decl) const;

public:
// Caching.
bool isCached() const { return true; }
};

class ProtocolConformanceRefClassifyAsThrowsRequest :
public SimpleRequest<ProtocolConformanceRefClassifyAsThrowsRequest,
bool(ProtocolConformanceRef),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

// Evaluation.
bool
evaluate(Evaluator &evaluator, ProtocolConformanceRef conformanceRef) const;

public:
// Caching.
bool isCached() const { return true; }
};

/// Determine whether the given declaration is 'final'.
class IsFinalRequest :
public SimpleRequest<IsFinalRequest,
Expand Down Expand Up @@ -734,6 +772,26 @@ void simple_display(llvm::raw_ostream &out, FragileFunctionKind value);

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

class FunctionRethrowingKindRequest :
public SimpleRequest<FunctionRethrowingKindRequest,
FunctionRethrowingKind(AbstractFunctionDecl*),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

// Evaluation.
FunctionRethrowingKind evaluate(Evaluator &evaluator, AbstractFunctionDecl *decl) const;

public:
// Caching.
bool isCached() const { return true; }
};

void simple_display(llvm::raw_ostream &out, FunctionRethrowingKind value);

/// Request the custom attribute which attaches a result builder to the
/// given declaration.
class AttachedResultBuilderRequest :
Expand Down
8 changes: 8 additions & 0 deletions include/swift/AST/TypeCheckerTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ SWIFT_REQUEST(TypeChecker, RequiresOpaqueModifyCoroutineRequest,
bool(AbstractStorageDecl *), SeparatelyCached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, FragileFunctionKindRequest,
FragileFunctionKind(DeclContext *), Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, FunctionRethrowingKindRequest,
FunctionRethrowingKind(AbstractFunctionDecl *), Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, SelfAccessKindRequest, SelfAccessKind(FuncDecl *),
SeparatelyCached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, StorageImplInfoRequest,
Expand Down Expand Up @@ -260,6 +262,12 @@ SWIFT_REQUEST(TypeChecker, ResolveImplicitMemberRequest,
SWIFT_REQUEST(TypeChecker, ResolveTypeEraserTypeRequest,
Type(ProtocolDecl *, TypeEraserAttr *),
SeparatelyCached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, ProtocolRethrowsRequirementsRequest,
ProtocolRethrowsRequirementList(ProtocolDecl *),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, ProtocolConformanceRefClassifyAsThrowsRequest,
bool(ProtocolConformanceRef),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, ResolveTypeRequest,
Type (const TypeResolution *, TypeRepr *, GenericParamList *),
Uncached, NoLocationInfo)
Expand Down
30 changes: 30 additions & 0 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@ struct ASTContext::Implementation {
/// The declaration of 'Sequence.makeIterator()'.
FuncDecl *MakeIterator = nullptr;

/// The declaration of 'AsyncSequence.makeAsyncIterator()'.
FuncDecl *MakeAsyncIterator = nullptr;

/// The declaration of Swift.Optional<T>.Some.
EnumElementDecl *OptionalSomeDecl = nullptr;

Expand Down Expand Up @@ -772,6 +775,31 @@ FuncDecl *ASTContext::getSequenceMakeIterator() const {
return nullptr;
}

FuncDecl *ASTContext::getAsyncSequenceMakeAsyncIterator() const {
if (getImpl().MakeAsyncIterator) {
return getImpl().MakeAsyncIterator;
}

auto proto = getProtocol(KnownProtocolKind::AsyncSequence);
if (!proto)
return nullptr;

for (auto result : proto->lookupDirect(Id_makeAsyncIterator)) {
if (result->getDeclContext() != proto)
continue;

if (auto func = dyn_cast<FuncDecl>(result)) {
if (func->getParameters()->size() != 0)
continue;

getImpl().MakeAsyncIterator = func;
return func;
}
}

return nullptr;
}

#define KNOWN_STDLIB_TYPE_DECL(NAME, DECL_CLASS, NUM_GENERIC_PARAMS) \
DECL_CLASS *ASTContext::get##NAME##Decl() const { \
if (getImpl().NAME##Decl) \
Expand Down Expand Up @@ -943,6 +971,8 @@ ProtocolDecl *ASTContext::getProtocol(KnownProtocolKind kind) const {
M = getLoadedModule(Id_Differentiation);
break;
case KnownProtocolKind::Actor:
case KnownProtocolKind::AsyncSequence:
case KnownProtocolKind::AsyncIteratorProtocol:
M = getLoadedModule(Id_Concurrency);
break;
default:
Expand Down
Loading