Skip to content

Sema: Start abstracting out the 'effect' in rethrows-checking logic #36029

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 3 commits into from
Feb 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions include/swift/AST/ASTTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ SWIFT_TYPEID(PropertyWrapperTypeInfo)
SWIFT_TYPEID(Requirement)
SWIFT_TYPEID(ResilienceExpansion)
SWIFT_TYPEID(FragileFunctionKind)
SWIFT_TYPEID(FunctionRethrowingKind)
SWIFT_TYPEID(ProtocolRethrowsRequirementList)
SWIFT_TYPEID(PolymorphicEffectKind)
SWIFT_TYPEID(PolymorphicEffectRequirementList)
SWIFT_TYPEID(TangentPropertyInfo)
SWIFT_TYPEID(SymbolSourceMap)
SWIFT_TYPEID(Type)
Expand Down
4 changes: 2 additions & 2 deletions include/swift/AST/ASTTypeIDs.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ class ProtocolDecl;
class Requirement;
enum class ResilienceExpansion : unsigned;
struct FragileFunctionKind;
enum class FunctionRethrowingKind : uint8_t;
class ProtocolRethrowsRequirementList;
enum class PolymorphicEffectKind : uint8_t;
class PolymorphicEffectRequirementList;
class SourceFile;
class SymbolSourceMap;
struct TangentPropertyInfo;
Expand Down
20 changes: 15 additions & 5 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,12 @@ namespace swift {
struct PropertyWrapperTypeInfo;
struct PropertyWrapperMutability;
class ProtocolDecl;
class ProtocolRethrowsRequirementList;
class PolymorphicEffectRequirementList;
class ProtocolType;
struct RawComment;
enum class ResilienceExpansion : unsigned;
enum class FunctionRethrowingKind : uint8_t;
enum class EffectKind : uint8_t;
enum class PolymorphicEffectKind : uint8_t;
class TrailingWhereClause;
class TypeAliasDecl;
class Stmt;
Expand Down Expand Up @@ -4117,8 +4118,11 @@ class ProtocolDecl final : public NominalTypeDecl {
/// contain 'Self' in 'parameter' or 'other' position.
bool existentialTypeSupported() const;

ProtocolRethrowsRequirementList getRethrowingRequirements() const;
bool isRethrowingProtocol() const;
/// Returns a list of protocol requirements that must be assessed to
/// determine a concrete's conformance effect polymorphism kind.
PolymorphicEffectRequirementList getPolymorphicEffectRequirements(
EffectKind kind) const;
bool hasPolymorphicEffect(EffectKind kind) const;

/// Determine whether this is a "marker" protocol, meaning that is indicates
/// semantics but has no corresponding witness table.
Expand Down Expand Up @@ -5740,7 +5744,13 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
/// Returns true if the function body throws.
bool hasThrows() const { return Bits.AbstractFunctionDecl.Throws; }

FunctionRethrowingKind getRethrowingKind() const;
/// Returns if the function throws or is async.
bool hasEffect(EffectKind kind) const;

/// Returns if the function is 'rethrows' or 'reasync'.
bool hasPolymorphicEffect(EffectKind kind) const;

PolymorphicEffectKind getPolymorphicEffectKind(EffectKind kind) const;

// FIXME: Hack that provides names with keyword arguments for accessors.
DeclName getEffectiveFullName() const;
Expand Down
66 changes: 44 additions & 22 deletions include/swift/AST/Effects.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,15 @@
//
//===----------------------------------------------------------------------===//
//
// This file defines some data types for rethrows and reasync effects.
// This file defines some data types used for 'rethrows' and `reasync` checking.
//
// We refer to 'throws' and 'async' as "effects". A function might have either or
// both effects.
//
// A function is _effect polymorphic_ if its effect depends on the call site.
// This can either be unconditional (the usual 'throws' or 'async' case), or it
// can depend on either its arguments or conformances (these are 'rethrows' and
// 'reasync' functions).
//
//===----------------------------------------------------------------------===//

Expand All @@ -27,50 +35,64 @@ class raw_ostream;

namespace swift {

enum class EffectKind : uint8_t {
Throws,
Async
};

void simple_display(llvm::raw_ostream &out, const EffectKind kind);

class ValueDecl;

class ProtocolRethrowsRequirementList {
using ThrowingRequirements = ArrayRef<AbstractFunctionDecl *>;
using ThrowingConformances = ArrayRef<std::pair<Type, ProtocolDecl *>>;
class PolymorphicEffectRequirementList {
using Requirements = ArrayRef<AbstractFunctionDecl *>;
using Conformances = ArrayRef<std::pair<Type, ProtocolDecl *>>;
private:
ThrowingRequirements requirements;
ThrowingConformances conformances;
Requirements requirements;
Conformances conformances;

public:
ProtocolRethrowsRequirementList(ThrowingRequirements requirements,
ThrowingConformances conformances)
PolymorphicEffectRequirementList(Requirements requirements,
Conformances conformances)
: requirements(requirements), conformances(conformances) {}
ProtocolRethrowsRequirementList() {}
PolymorphicEffectRequirementList() {}

ThrowingRequirements getRequirements() const {
Requirements getRequirements() const {
return requirements;
}

ThrowingConformances getConformances() const {
Conformances getConformances() const {
return conformances;
}
};

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

enum class FunctionRethrowingKind : uint8_t {
/// The function is not throwing
enum class PolymorphicEffectKind : uint8_t {
/// The function does not have this effect at all.
None,

/// The function rethrows by closure
ByClosure,
/// The function has this effect if at least one closure argument has it.
///
/// This is the ordinary 'rethrows' /'reasync' case.
ByClosure,

/// The function rethrows by conformance
ByConformance,
/// The function has this effect if at least one of its conformances has it.
///
/// This is the conformance-based 'rethrows' /'reasync' case.
ByConformance,

/// The function throws
Throws,
/// The function has this effect unconditionally.
///
/// This is a plain old 'throws' / 'async' function.
Always,

/// The function throwing determinate is invalid
/// The function declaration was invalid.
Invalid
};

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

} // end namespace swift

Expand Down
3 changes: 2 additions & 1 deletion include/swift/AST/ProtocolConformanceRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ namespace swift {

class ConcreteDeclRef;
class ProtocolConformance;
enum class EffectKind : uint8_t;

/// A ProtocolConformanceRef is a handle to a protocol conformance which
/// may be either concrete or abstract.
Expand Down Expand Up @@ -171,7 +172,7 @@ class ProtocolConformanceRef {
/// be satisfied.
ArrayRef<Requirement> getConditionalRequirements() const;

bool classifyAsThrows() const;
bool hasEffect(EffectKind kind) const;
};

void simple_display(llvm::raw_ostream &out, ProtocolConformanceRef conformanceRef);
Expand Down
29 changes: 16 additions & 13 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,9 +313,9 @@ class ExistentialTypeSupportedRequest :
void cacheResult(bool value) const;
};

class ProtocolRethrowsRequirementsRequest :
public SimpleRequest<ProtocolRethrowsRequirementsRequest,
ProtocolRethrowsRequirementList(ProtocolDecl *),
class PolymorphicEffectRequirementsRequest :
public SimpleRequest<PolymorphicEffectRequirementsRequest,
PolymorphicEffectRequirementList(EffectKind, ProtocolDecl *),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;
Expand All @@ -324,17 +324,17 @@ class ProtocolRethrowsRequirementsRequest :
friend SimpleRequest;

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

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

class ProtocolConformanceClassifyAsThrowsRequest :
public SimpleRequest<ProtocolConformanceClassifyAsThrowsRequest,
bool(ProtocolConformance *),
class ConformanceHasEffectRequest :
public SimpleRequest<ConformanceHasEffectRequest,
bool(EffectKind, ProtocolConformance *),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;
Expand All @@ -344,7 +344,8 @@ class ProtocolConformanceClassifyAsThrowsRequest :

// Evaluation.
bool
evaluate(Evaluator &evaluator, ProtocolConformance *conformance) const;
evaluate(Evaluator &evaluator, EffectKind kind,
ProtocolConformance *conformance) const;

public:
// Caching.
Expand Down Expand Up @@ -774,9 +775,9 @@ 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*),
class PolymorphicEffectKindRequest :
public SimpleRequest<PolymorphicEffectKindRequest,
PolymorphicEffectKind(EffectKind, AbstractFunctionDecl*),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;
Expand All @@ -785,7 +786,9 @@ class FunctionRethrowingKindRequest :
friend SimpleRequest;

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

public:
// Caching.
Expand Down
13 changes: 7 additions & 6 deletions include/swift/AST/TypeCheckerTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,9 @@ 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, PolymorphicEffectKindRequest,
PolymorphicEffectKind(EffectKind, AbstractFunctionDecl *),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, SelfAccessKindRequest, SelfAccessKind(FuncDecl *),
SeparatelyCached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, StorageImplInfoRequest,
Expand Down Expand Up @@ -269,11 +270,11 @@ SWIFT_REQUEST(TypeChecker, ResolveImplicitMemberRequest,
SWIFT_REQUEST(TypeChecker, ResolveTypeEraserTypeRequest,
Type(ProtocolDecl *, TypeEraserAttr *),
SeparatelyCached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, ProtocolRethrowsRequirementsRequest,
ProtocolRethrowsRequirementList(ProtocolDecl *),
SWIFT_REQUEST(TypeChecker, PolymorphicEffectRequirementsRequest,
PolymorphicEffectRequirementList(EffectKind, ProtocolDecl *),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, ProtocolConformanceClassifyAsThrowsRequest,
bool(ProtocolConformanceRef),
SWIFT_REQUEST(TypeChecker, ConformanceHasEffectRequest,
bool(EffectKind, ProtocolConformanceRef),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, ResolveTypeRequest,
Type (const TypeResolution *, TypeRepr *, GenericParamList *),
Expand Down
10 changes: 5 additions & 5 deletions lib/AST/ASTVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1804,19 +1804,19 @@ class Verifier : public ASTWalker {
Out << "\n";
abort();
} else if (E->throws() && !FT->isThrowing()) {
FunctionRethrowingKind rethrowingKind = FunctionRethrowingKind::Invalid;
PolymorphicEffectKind rethrowingKind = PolymorphicEffectKind::Invalid;
if (auto DRE = dyn_cast<DeclRefExpr>(E->getFn())) {
if (auto fnDecl = dyn_cast<AbstractFunctionDecl>(DRE->getDecl())) {
rethrowingKind = fnDecl->getRethrowingKind();
rethrowingKind = fnDecl->getPolymorphicEffectKind(EffectKind::Throws);
}
} else if (auto OCDRE = dyn_cast<OtherConstructorDeclRefExpr>(E->getFn())) {
if (auto fnDecl = dyn_cast<AbstractFunctionDecl>(OCDRE->getDecl())) {
rethrowingKind = fnDecl->getRethrowingKind();
rethrowingKind = fnDecl->getPolymorphicEffectKind(EffectKind::Throws);
}
}

if (rethrowingKind != FunctionRethrowingKind::ByConformance &&
rethrowingKind != FunctionRethrowingKind::Throws) {
if (rethrowingKind != PolymorphicEffectKind::ByConformance &&
rethrowingKind != PolymorphicEffectKind::Always) {
Out << "apply expression is marked as throwing, but function operand"
"does not have a throwing function type\n";
E->dump(Out);
Expand Down
Loading