Skip to content
18 changes: 18 additions & 0 deletions include/swift/AST/AnyFunctionRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,24 @@ class AnyFunctionRef {
return TheFunction.get<AbstractClosureExpr *>()->getType();
}

Type getThrownErrorType() const {
if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>()) {
if (Type thrownError = AFD->getThrownInterfaceType())
return AFD->mapTypeIntoContext(thrownError);

return Type();
}

Type closureType = TheFunction.get<AbstractClosureExpr *>()->getType();
if (!closureType)
return Type();

if (auto closureFnType = closureType->getAs<AnyFunctionType>())
return closureFnType->getThrownError();

return Type();
}

Type getBodyResultType() const {
if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>()) {
if (auto *FD = dyn_cast<FuncDecl>(AFD))
Expand Down
9 changes: 6 additions & 3 deletions include/swift/AST/CASTBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -341,24 +341,26 @@ void AbstractFunctionDecl_setBody(void *opaqueBody, void *opaqueDecl);

SWIFT_NAME("FuncDecl_create(astContext:declContext:staticLoc:funcKeywordLoc:"
"name:nameLoc:genericParamList:parameterList:asyncSpecifierLoc:"
"throwsSpecifierLoc:returnType:genericWhereClause:)")
"throwsSpecifierLoc:thrownType:returnType:genericWhereClause:)")
struct BridgedDeclContextAndDecl
FuncDecl_create(BridgedASTContext cContext, BridgedDeclContext cDeclContext,
BridgedSourceLoc cStaticLoc, BridgedSourceLoc cFuncKeywordLoc,
BridgedIdentifier cName, BridgedSourceLoc cNameLoc,
void *_Nullable opaqueGenericParamList,
void *opaqueParameterList, BridgedSourceLoc cAsyncLoc,
BridgedSourceLoc cThrowsLoc, void *_Nullable opaqueReturnType,
BridgedSourceLoc cThrowsLoc, void *_Nullable opaqueThrownType,
void *_Nullable opaqueReturnType,
void *_Nullable opaqueGenericWhereClause);

SWIFT_NAME("ConstructorDecl_create(astContext:declContext:initKeywordLoc:"
"failabilityMarkLoc:isIUO:genericParamList:parameterList:"
"asyncSpecifierLoc:throwsSpecifierLoc:genericWhereClause:)")
"asyncSpecifierLoc:throwsSpecifierLoc:thrownType:genericWhereClause:)")
BridgedDeclContextAndDecl ConstructorDecl_create(
BridgedASTContext cContext, BridgedDeclContext cDeclContext,
BridgedSourceLoc cInitKeywordLoc, BridgedSourceLoc cFailabilityMarkLoc,
_Bool isIUO, void *_Nullable opaqueGenericParams, void *opaqueParameterList,
BridgedSourceLoc cAsyncLoc, BridgedSourceLoc cThrowsLoc,
void *_Nullable opaqueThrownType,
void *_Nullable opaqueGenericWhereClause);

SWIFT_NAME("DestructorDecl_create(astContext:declContext:deinitKeywordLoc:)")
Expand Down Expand Up @@ -587,6 +589,7 @@ void *EmptyCompositionTypeRepr_create(BridgedASTContext cContext,
void *FunctionTypeRepr_create(BridgedASTContext cContext, void *argsTy,
BridgedSourceLoc cAsyncLoc,
BridgedSourceLoc cThrowsLoc,
void * _Nullable thrownType,
BridgedSourceLoc cArrowLoc, void *returnType);
void *GenericIdentTypeRepr_create(BridgedASTContext cContext,
BridgedIdentifier name,
Expand Down
44 changes: 38 additions & 6 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -6836,6 +6836,7 @@ void simple_display(llvm::raw_ostream &out, BodyAndFingerprint value);
/// Base class for function-like declarations.
class AbstractFunctionDecl : public GenericContext, public ValueDecl {
friend class NeedsNewVTableEntryRequest;
friend class ThrownTypeRequest;

public:
/// records the kind of SILGen-synthesized body this decl represents
Expand Down Expand Up @@ -6942,6 +6943,9 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
/// Location of the 'throws' token.
SourceLoc ThrowsLoc;

/// The error type that is being thrown.
TypeLoc ThrownType;

struct {
unsigned NeedsNewVTableEntryComputed : 1;
unsigned NeedsNewVTableEntry : 1;
Expand All @@ -6950,12 +6954,13 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
AbstractFunctionDecl(DeclKind Kind, DeclContext *Parent, DeclName Name,
SourceLoc NameLoc, bool Async, SourceLoc AsyncLoc,
bool Throws, SourceLoc ThrowsLoc,
TypeLoc ThrownTy,
bool HasImplicitSelfDecl,
GenericParamList *GenericParams)
: GenericContext(DeclContextKind::AbstractFunctionDecl, Parent,
GenericParams),
ValueDecl(Kind, Parent, Name, NameLoc), BodyAndFP(), AsyncLoc(AsyncLoc),
ThrowsLoc(ThrowsLoc) {
ThrowsLoc(ThrowsLoc), ThrownType(ThrownTy) {
setBodyKind(BodyKind::None);
Bits.AbstractFunctionDecl.HasImplicitSelfDecl = HasImplicitSelfDecl;
Bits.AbstractFunctionDecl.Overridden = false;
Expand Down Expand Up @@ -7053,6 +7058,21 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
/// Returns true if the function body throws.
bool hasThrows() const { return Bits.AbstractFunctionDecl.Throws; }

/// Retrieves the type representation for the thrown type.
TypeRepr *getThrownTypeRepr() const {
return ThrownType.getTypeRepr();
}

/// Retrieves the thrown interface type.
Type getThrownInterfaceType() const;

/// Retrieve the "effective" thrown interface type, or llvm::None if
/// this function cannot throw.
///
/// Functions with untyped throws will produce "any Error", functions that
/// cannot throw or are specified to throw "Never" will return llvm::None.
llvm::Optional<Type> getEffectiveThrownInterfaceType() const;

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

Expand Down Expand Up @@ -7443,12 +7463,13 @@ class FuncDecl : public AbstractFunctionDecl {
DeclName Name, SourceLoc NameLoc,
bool Async, SourceLoc AsyncLoc,
bool Throws, SourceLoc ThrowsLoc,
TypeLoc ThrownTy,
bool HasImplicitSelfDecl,
GenericParamList *GenericParams, DeclContext *Parent)
: AbstractFunctionDecl(Kind, Parent,
Name, NameLoc,
Async, AsyncLoc,
Throws, ThrowsLoc,
Throws, ThrowsLoc, ThrownTy,
HasImplicitSelfDecl, GenericParams),
StaticLoc(StaticLoc), FuncLoc(FuncLoc) {
assert(!Name.getBaseName().isSpecial());
Expand All @@ -7473,6 +7494,7 @@ class FuncDecl : public AbstractFunctionDecl {
DeclName Name, SourceLoc NameLoc,
bool Async, SourceLoc AsyncLoc,
bool Throws, SourceLoc ThrowsLoc,
TypeLoc ThrownTy,
GenericParamList *GenericParams,
DeclContext *Parent,
ClangNode ClangN);
Expand All @@ -7496,27 +7518,31 @@ class FuncDecl : public AbstractFunctionDecl {
static FuncDecl *createDeserialized(ASTContext &Context,
StaticSpellingKind StaticSpelling,
DeclName Name, bool Async, bool Throws,
Type ThrownType,
GenericParamList *GenericParams,
Type FnRetType, DeclContext *Parent);

static FuncDecl *create(ASTContext &Context, SourceLoc StaticLoc,
StaticSpellingKind StaticSpelling, SourceLoc FuncLoc,
DeclName Name, SourceLoc NameLoc, bool Async,
SourceLoc AsyncLoc, bool Throws, SourceLoc ThrowsLoc,
TypeRepr *ThrownTyR,
GenericParamList *GenericParams,
ParameterList *BodyParams, TypeRepr *ResultTyR,
DeclContext *Parent);

static FuncDecl *createImplicit(ASTContext &Context,
StaticSpellingKind StaticSpelling,
DeclName Name, SourceLoc NameLoc, bool Async,
bool Throws, GenericParamList *GenericParams,
bool Throws, Type ThrownType,
GenericParamList *GenericParams,
ParameterList *BodyParams, Type FnRetType,
DeclContext *Parent);

static FuncDecl *createImported(ASTContext &Context, SourceLoc FuncLoc,
DeclName Name, SourceLoc NameLoc, bool Async,
bool Throws, ParameterList *BodyParams,
bool Throws, Type ThrownType,
ParameterList *BodyParams,
Type FnRetType,
GenericParamList *GenericParams,
DeclContext *Parent, ClangNode ClangN);
Expand Down Expand Up @@ -7649,11 +7675,12 @@ class AccessorDecl final : public FuncDecl {
AccessorKind accessorKind, AbstractStorageDecl *storage,
SourceLoc staticLoc, StaticSpellingKind staticSpelling,
bool async, SourceLoc asyncLoc, bool throws, SourceLoc throwsLoc,
TypeLoc thrownTy,
bool hasImplicitSelfDecl, DeclContext *parent)
: FuncDecl(DeclKind::Accessor, staticLoc, staticSpelling,
/*func loc*/ declLoc,
/*name*/ Identifier(), /*name loc*/ declLoc, async, asyncLoc,
throws, throwsLoc, hasImplicitSelfDecl,
throws, throwsLoc, thrownTy, hasImplicitSelfDecl,
/*genericParams*/ nullptr, parent),
AccessorKeywordLoc(accessorKeywordLoc), Storage(storage) {
assert(!async || accessorKind == AccessorKind::Get
Expand All @@ -7666,6 +7693,7 @@ class AccessorDecl final : public FuncDecl {
AccessorKind accessorKind, AbstractStorageDecl *storage,
SourceLoc staticLoc, StaticSpellingKind staticSpelling, bool async,
SourceLoc asyncLoc, bool throws, SourceLoc throwsLoc,
TypeLoc thrownTy,
DeclContext *parent, ClangNode clangNode);

llvm::Optional<bool> getCachedIsTransparent() const {
Expand All @@ -7682,14 +7710,16 @@ class AccessorDecl final : public FuncDecl {
AbstractStorageDecl *storage,
StaticSpellingKind staticSpelling,
bool async, bool throws,
Type thrownType,
Type fnRetType, DeclContext *parent);

static AccessorDecl *
create(ASTContext &ctx, SourceLoc declLoc, SourceLoc accessorKeywordLoc,
AccessorKind accessorKind, AbstractStorageDecl *storage,
SourceLoc staticLoc, StaticSpellingKind staticSpelling, bool async,
SourceLoc asyncLoc, bool throws, SourceLoc throwsLoc,
ParameterList *parameterList, Type fnRetType, DeclContext *parent,
TypeLoc thrownType, ParameterList *parameterList, Type fnRetType,
DeclContext *parent,
ClangNode clangNode = ClangNode());

SourceLoc getAccessorKeywordLoc() const { return AccessorKeywordLoc; }
Expand Down Expand Up @@ -8052,6 +8082,7 @@ class ConstructorDecl : public AbstractFunctionDecl {
bool Failable, SourceLoc FailabilityLoc,
bool Async, SourceLoc AsyncLoc,
bool Throws, SourceLoc ThrowsLoc,
TypeLoc thrownTy,
ParameterList *BodyParams,
GenericParamList *GenericParams,
DeclContext *Parent);
Expand All @@ -8062,6 +8093,7 @@ class ConstructorDecl : public AbstractFunctionDecl {
bool failable, SourceLoc failabilityLoc,
bool async, SourceLoc asyncLoc,
bool throws, SourceLoc throwsLoc,
Type thrownTy,
ParameterList *bodyParams, GenericParamList *genericParams,
DeclContext *parent);

Expand Down
7 changes: 7 additions & 0 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -1690,6 +1690,13 @@ ERROR(attr_type_eraser_expected_type_name,none,
ERROR(attr_type_eraser_expected_rparen,none,
"expected ')' after type name for @_typeEraser", ())

ERROR(expected_thrown_error_type,none,
"expected thrown error type after 'throws('", ())
ERROR(expected_rparen_after_thrown_error_type,none,
"expected ')' after thrown error type", ())
ERROR(rethrows_with_thrown_error,none,
"'rethrows' cannot be combined with a specific thrown error type", ())

ERROR(attr_private_import_expected_rparen,none,
"expected ')' after function name for @_private", ())
ERROR(attr_private_import_expected_sourcefile, none,
Expand Down
18 changes: 13 additions & 5 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,9 @@ ERROR(cannot_convert_to_return_type_nil,none,
"'nil' is incompatible with return type %0", (Type))

ERROR(cannot_convert_thrown_type,none,
"thrown expression type %0 does not conform to 'Error'", (Type))
"thrown expression type %0 %select{cannot be converted to error type %1|"
"does not conform to 'Error'}2",
(Type, Type, bool))
ERROR(cannot_throw_error_code,none,
"thrown error code type %0 does not conform to 'Error'; construct an %1 "
"instance", (Type, Type))
Expand Down Expand Up @@ -2265,10 +2267,10 @@ ERROR(function_type_access,none,
"%select{private|fileprivate|internal|package|%error|%error}1|private or fileprivate}2"
"|cannot be declared "
"%select{in this context|fileprivate|internal|package|public|open}1}0 "
"because its %select{parameter|result}5 uses "
"because its %select{parameter|thrown error|result}5 uses "
"%select{a private|a fileprivate|an internal|a package|an '@_spi'|an '@_spi'}3"
"%select{| API wrapper}6 type",
(bool, AccessLevel, bool, AccessLevel, unsigned, bool, bool))
(bool, AccessLevel, bool, AccessLevel, unsigned, unsigned, bool))
ERROR(function_type_spi,none,
"%select{function|method|initializer}0 "
"cannot be declared '@_spi' "
Expand All @@ -2280,10 +2282,10 @@ WARNING(function_type_access_warn,none,
"%select{function|method|initializer}4 "
"%select{should be declared %select{private|fileprivate|internal|package|%error|%error}1"
"|should not be declared %select{in this context|fileprivate|internal|package|public|open}1}0 "
"because its %select{parameter|result}5 uses "
"because its %select{parameter|thrown error|result}5 uses "
"%select{a private|a fileprivate|an internal|a package|%error|%error}3 "
"%select{|API wrapper}6 type",
(bool, AccessLevel, bool, AccessLevel, unsigned, bool, bool))
(bool, AccessLevel, bool, AccessLevel, unsigned, unsigned, bool))
ERROR(function_type_usable_from_inline,none,
"the %select{parameter|result}1%select{| API wrapper}2 of a "
"'@usableFromInline' %select{function|method|initializer}0 "
Expand Down Expand Up @@ -5048,6 +5050,12 @@ WARNING(no_throw_in_try,none,
WARNING(no_throw_in_do_with_catch,none,
"'catch' block is unreachable because no errors are thrown in 'do' block", ())

ERROR(experimental_typed_throws,none,
"typed throws is an experimental feature", ())

ERROR(thrown_type_not_error,none,
"thrown type %0 does not conform to the 'Error' protocol", (Type))

//------------------------------------------------------------------------------
// MARK: Concurrency
//------------------------------------------------------------------------------
Expand Down
48 changes: 41 additions & 7 deletions include/swift/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -3847,6 +3847,13 @@ class AbstractClosureExpr : public DeclContext, public Expr {
/// Return whether this closure is throwing when fully applied.
bool isBodyThrowing() const;

/// Retrieve the "effective" thrown interface type, or llvm::None if
/// this closure cannot throw.
///
/// Closures with untyped throws will produce "any Error", functions that
/// cannot throw or are specified to throw "Never" will return llvm::None.
llvm::Optional<Type> getEffectiveThrownType() const;

/// \brief Return whether this closure is async when fully applied.
bool isBodyAsync() const;

Expand Down Expand Up @@ -3981,6 +3988,9 @@ class ClosureExpr : public AbstractClosureExpr {
/// The location of the "in", if present.
SourceLoc InLoc;

/// The explcitly-specified thrown type.
TypeExpr *ThrownType;

/// The explicitly-specified result type.
llvm::PointerIntPair<TypeExpr *, 2, BodyState> ExplicitResultTypeAndBodyState;

Expand All @@ -3991,14 +4001,14 @@ class ClosureExpr : public AbstractClosureExpr {
ClosureExpr(const DeclAttributes &attributes,
SourceRange bracketRange, VarDecl *capturedSelfDecl,
ParameterList *params, SourceLoc asyncLoc, SourceLoc throwsLoc,
SourceLoc arrowLoc, SourceLoc inLoc, TypeExpr *explicitResultType,
DeclContext *parent)
TypeExpr *thrownType, SourceLoc arrowLoc, SourceLoc inLoc,
TypeExpr *explicitResultType, DeclContext *parent)
: AbstractClosureExpr(ExprKind::Closure, Type(), /*Implicit=*/false,
parent),
Attributes(attributes), BracketRange(bracketRange),
CapturedSelfDecl(capturedSelfDecl),
AsyncLoc(asyncLoc), ThrowsLoc(throwsLoc), ArrowLoc(arrowLoc),
InLoc(inLoc),
InLoc(inLoc), ThrownType(thrownType),
ExplicitResultTypeAndBodyState(explicitResultType, BodyState::Parsed),
Body(nullptr) {
setParameterList(params);
Expand Down Expand Up @@ -4092,6 +4102,24 @@ class ClosureExpr : public AbstractClosureExpr {
return ThrowsLoc;
}

/// Retrieve the explicitly-thrown type.
Type getExplicitThrownType() const {
if (ThrownType)
return ThrownType->getInstanceType();

return nullptr;
}

void setExplicitThrownType(Type thrownType);

/// Retrieve the explicitly-thrown type representation.
TypeRepr *getExplicitThrownTypeRepr() const {
if (ThrownType)
return ThrownType->getTypeRepr();

return nullptr;
}

Type getExplicitResultType() const {
assert(hasExplicitResultType() && "No explicit result type");
return ExplicitResultTypeAndBodyState.getPointer()->getInstanceType();
Expand Down Expand Up @@ -5177,24 +5205,30 @@ class ArrowExpr : public Expr {
SourceLoc ArrowLoc;
Expr *Args;
Expr *Result;
Expr *ThrownType;

public:
ArrowExpr(Expr *Args, SourceLoc AsyncLoc, SourceLoc ThrowsLoc,
SourceLoc ArrowLoc, Expr *Result)
Expr *ThrownType, SourceLoc ArrowLoc, Expr *Result)
: Expr(ExprKind::Arrow, /*implicit=*/false, Type()),
AsyncLoc(AsyncLoc), ThrowsLoc(ThrowsLoc), ArrowLoc(ArrowLoc), Args(Args),
Result(Result)
Result(Result), ThrownType(ThrownType)
{ }

ArrowExpr(SourceLoc AsyncLoc, SourceLoc ThrowsLoc, SourceLoc ArrowLoc)
ArrowExpr(SourceLoc AsyncLoc, SourceLoc ThrowsLoc, Expr *ThrownType,
SourceLoc ArrowLoc)
: Expr(ExprKind::Arrow, /*implicit=*/false, Type()),
AsyncLoc(AsyncLoc), ThrowsLoc(ThrowsLoc), ArrowLoc(ArrowLoc),
Args(nullptr), Result(nullptr)
Args(nullptr), Result(nullptr), ThrownType(ThrownType)
{ }

Expr *getArgsExpr() const { return Args; }
void setArgsExpr(Expr *E) { Args = E; }
Expr *getResultExpr() const { return Result; }
void setResultExpr(Expr *E) { Result = E; }
Expr *getThrownTypeExpr() const { return ThrownType; }
void setThrownTypeExpr(Expr *E) { ThrownType = E; }

SourceLoc getAsyncLoc() const { return AsyncLoc; }
SourceLoc getThrowsLoc() const { return ThrowsLoc; }
SourceLoc getArrowLoc() const { return ArrowLoc; }
Expand Down
Loading