Skip to content

Commit 51eed19

Browse files
committed
[Typed throws] Type system support for typed throws.
Add the thrown type into the AST representation of function types, mapping from function type representations and declarations into the appropriate thrown type. Add tests for serialization, printing, and basic equivalence of function types that have thrown errors.
1 parent ef64209 commit 51eed19

34 files changed

+526
-117
lines changed

include/swift/AST/Decl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6836,6 +6836,7 @@ void simple_display(llvm::raw_ostream &out, BodyAndFingerprint value);
68366836
/// Base class for function-like declarations.
68376837
class AbstractFunctionDecl : public GenericContext, public ValueDecl {
68386838
friend class NeedsNewVTableEntryRequest;
6839+
friend class ThrownTypeRequest;
68396840

68406841
public:
68416842
/// records the kind of SILGen-synthesized body this decl represents

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5048,6 +5048,12 @@ WARNING(no_throw_in_try,none,
50485048
WARNING(no_throw_in_do_with_catch,none,
50495049
"'catch' block is unreachable because no errors are thrown in 'do' block", ())
50505050

5051+
ERROR(experimental_typed_throws,none,
5052+
"typed throws is an experimental feature", ())
5053+
5054+
ERROR(thrown_type_not_error,none,
5055+
"thrown type %0 does not conform to the 'Error' protocol", (Type))
5056+
50515057
//------------------------------------------------------------------------------
50525058
// MARK: Concurrency
50535059
//------------------------------------------------------------------------------

include/swift/AST/ExtInfo.h

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -370,37 +370,41 @@ class ASTExtInfoBuilder {
370370

371371
ClangTypeInfo clangTypeInfo;
372372
Type globalActor;
373+
Type thrownError;
373374

374375
using Representation = FunctionTypeRepresentation;
375376

376377
ASTExtInfoBuilder(
377-
unsigned bits, ClangTypeInfo clangTypeInfo, Type globalActor
378-
) : bits(bits), clangTypeInfo(clangTypeInfo), globalActor(globalActor) {}
378+
unsigned bits, ClangTypeInfo clangTypeInfo, Type globalActor,
379+
Type thrownError
380+
) : bits(bits), clangTypeInfo(clangTypeInfo), globalActor(globalActor),
381+
thrownError(thrownError) {}
379382

380383
public:
381384
/// An ExtInfoBuilder for a typical Swift function: @convention(swift),
382385
/// @escaping, non-throwing, non-differentiable.
383386
ASTExtInfoBuilder()
384-
: ASTExtInfoBuilder(Representation::Swift, false, false,
387+
: ASTExtInfoBuilder(Representation::Swift, false, false, Type(),
385388
DifferentiabilityKind::NonDifferentiable, nullptr,
386389
Type()) {}
387390

388391
// Constructor for polymorphic type.
389-
ASTExtInfoBuilder(Representation rep, bool throws)
390-
: ASTExtInfoBuilder(rep, false, throws,
392+
ASTExtInfoBuilder(Representation rep, bool throws, Type thrownError)
393+
: ASTExtInfoBuilder(rep, false, throws, thrownError,
391394
DifferentiabilityKind::NonDifferentiable, nullptr,
392395
Type()) {}
393396

394397
// Constructor with no defaults.
395398
ASTExtInfoBuilder(Representation rep, bool isNoEscape, bool throws,
399+
Type thrownError,
396400
DifferentiabilityKind diffKind, const clang::Type *type,
397401
Type globalActor)
398402
: ASTExtInfoBuilder(
399403
((unsigned)rep) | (isNoEscape ? NoEscapeMask : 0) |
400404
(throws ? ThrowsMask : 0) |
401405
(((unsigned)diffKind << DifferentiabilityMaskOffset) &
402406
DifferentiabilityMask),
403-
ClangTypeInfo(type), globalActor) {}
407+
ClangTypeInfo(type), globalActor, thrownError) {}
404408

405409
void checkInvariants() const;
406410

@@ -438,6 +442,7 @@ class ASTExtInfoBuilder {
438442
}
439443

440444
Type getGlobalActor() const { return globalActor; }
445+
Type getThrownError() const { return thrownError; }
441446

442447
constexpr bool hasSelfParam() const {
443448
switch (getSILRepresentation()) {
@@ -472,43 +477,48 @@ class ASTExtInfoBuilder {
472477
return ASTExtInfoBuilder((bits & ~RepresentationMask) | (unsigned)rep,
473478
shouldStoreClangType(rep) ? clangTypeInfo
474479
: ClangTypeInfo(),
475-
globalActor);
480+
globalActor, thrownError);
476481
}
477482
[[nodiscard]]
478483
ASTExtInfoBuilder withNoEscape(bool noEscape = true) const {
479484
return ASTExtInfoBuilder(noEscape ? (bits | NoEscapeMask)
480485
: (bits & ~NoEscapeMask),
481-
clangTypeInfo, globalActor);
486+
clangTypeInfo, globalActor, thrownError);
482487
}
483488
[[nodiscard]]
484489
ASTExtInfoBuilder withConcurrent(bool concurrent = true) const {
485490
return ASTExtInfoBuilder(concurrent ? (bits | SendableMask)
486491
: (bits & ~SendableMask),
487-
clangTypeInfo, globalActor);
492+
clangTypeInfo, globalActor, thrownError);
488493
}
489494
[[nodiscard]]
490495
ASTExtInfoBuilder withAsync(bool async = true) const {
491496
return ASTExtInfoBuilder(async ? (bits | AsyncMask)
492497
: (bits & ~AsyncMask),
493-
clangTypeInfo, globalActor);
498+
clangTypeInfo, globalActor, thrownError);
494499
}
495500
[[nodiscard]]
496-
ASTExtInfoBuilder withThrows(bool throws = true) const {
501+
ASTExtInfoBuilder withThrows(bool throws, Type thrownError) const {
497502
return ASTExtInfoBuilder(
498503
throws ? (bits | ThrowsMask) : (bits & ~ThrowsMask), clangTypeInfo,
499-
globalActor);
504+
globalActor, thrownError);
505+
}
506+
[[nodiscard]]
507+
ASTExtInfoBuilder withThrows() const {
508+
return withThrows(true, Type());
500509
}
501510
[[nodiscard]]
502511
ASTExtInfoBuilder
503512
withDifferentiabilityKind(DifferentiabilityKind differentiability) const {
504513
return ASTExtInfoBuilder(
505514
(bits & ~DifferentiabilityMask) |
506515
((unsigned)differentiability << DifferentiabilityMaskOffset),
507-
clangTypeInfo, globalActor);
516+
clangTypeInfo, globalActor, thrownError);
508517
}
509518
[[nodiscard]]
510519
ASTExtInfoBuilder withClangFunctionType(const clang::Type *type) const {
511-
return ASTExtInfoBuilder(bits, ClangTypeInfo(type), globalActor);
520+
return ASTExtInfoBuilder(
521+
bits, ClangTypeInfo(type), globalActor, thrownError);
512522
}
513523

514524
/// Put a SIL representation in the ExtInfo.
@@ -522,24 +532,26 @@ class ASTExtInfoBuilder {
522532
return ASTExtInfoBuilder((bits & ~RepresentationMask) | (unsigned)rep,
523533
shouldStoreClangType(rep) ? clangTypeInfo
524534
: ClangTypeInfo(),
525-
globalActor);
535+
globalActor, thrownError);
526536
}
527537

528538
[[nodiscard]]
529539
ASTExtInfoBuilder withGlobalActor(Type globalActor) const {
530-
return ASTExtInfoBuilder(bits, clangTypeInfo, globalActor);
540+
return ASTExtInfoBuilder(bits, clangTypeInfo, globalActor, thrownError);
531541
}
532542

533543
bool isEqualTo(ASTExtInfoBuilder other, bool useClangTypes) const {
534544
return bits == other.bits &&
535545
(useClangTypes ? (clangTypeInfo == other.clangTypeInfo) : true) &&
536-
globalActor.getPointer() == other.globalActor.getPointer();
546+
globalActor.getPointer() == other.globalActor.getPointer() &&
547+
thrownError.getPointer() == thrownError.getPointer();
537548
}
538549

539-
constexpr std::tuple<unsigned, const void *, const void *>
550+
constexpr std::tuple<unsigned, const void *, const void *, const void *>
540551
getFuncAttrKey() const {
541552
return std::make_tuple(
542-
bits, clangTypeInfo.getType(), globalActor.getPointer());
553+
bits, clangTypeInfo.getType(), globalActor.getPointer(),
554+
thrownError.getPointer());
543555
}
544556
}; // end ASTExtInfoBuilder
545557

@@ -560,8 +572,9 @@ class ASTExtInfo {
560572
// Only for use by ASTExtInfoBuilder::build. Don't use it elsewhere!
561573
ASTExtInfo(ASTExtInfoBuilder builder) : builder(builder) {}
562574

563-
ASTExtInfo(unsigned bits, ClangTypeInfo clangTypeInfo, Type globalActor)
564-
: builder(bits, clangTypeInfo, globalActor) {
575+
ASTExtInfo(unsigned bits, ClangTypeInfo clangTypeInfo, Type globalActor,
576+
Type thrownError)
577+
: builder(bits, clangTypeInfo, globalActor, thrownError) {
565578
builder.checkInvariants();
566579
};
567580

@@ -606,6 +619,7 @@ class ASTExtInfo {
606619
constexpr bool hasContext() const { return builder.hasContext(); }
607620

608621
Type getGlobalActor() const { return builder.getGlobalActor(); }
622+
Type getThrownError() const { return builder.getThrownError(); }
609623

610624
/// Helper method for changing the representation.
611625
///
@@ -635,8 +649,16 @@ class ASTExtInfo {
635649
///
636650
/// Prefer using \c ASTExtInfoBuilder::withThrows for chaining.
637651
[[nodiscard]]
638-
ASTExtInfo withThrows(bool throws = true) const {
639-
return builder.withThrows(throws).build();
652+
ASTExtInfo withThrows(bool throws, Type thrownError) const {
653+
return builder.withThrows(throws, thrownError).build();
654+
}
655+
656+
/// Helper method for changing only the throws field.
657+
///
658+
/// Prefer using \c ASTExtInfoBuilder::withThrows for chaining.
659+
[[nodiscard]]
660+
ASTExtInfo withThrows() const {
661+
return builder.withThrows(true, Type()).build();
640662
}
641663

642664
/// Helper method for changing only the async field.
@@ -656,7 +678,7 @@ class ASTExtInfo {
656678
return builder.isEqualTo(other.builder, useClangTypes);
657679
}
658680

659-
constexpr std::tuple<unsigned, const void *, const void *>
681+
constexpr std::tuple<unsigned, const void *, const void *, const void *>
660682
getFuncAttrKey() const {
661683
return builder.getFuncAttrKey();
662684
}

include/swift/AST/TypeCheckRequests.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2222,6 +2222,27 @@ class ParamSpecifierRequest
22222222
void cacheResult(ParamSpecifier value) const;
22232223
};
22242224

2225+
/// Determines the explicitly-written thrown result type of a function.
2226+
class ThrownTypeRequest
2227+
: public SimpleRequest<ThrownTypeRequest,
2228+
Type(AbstractFunctionDecl *),
2229+
RequestFlags::SeparatelyCached> {
2230+
public:
2231+
using SimpleRequest::SimpleRequest;
2232+
2233+
private:
2234+
friend SimpleRequest;
2235+
2236+
// Evaluation.
2237+
Type evaluate(Evaluator &evaluator, AbstractFunctionDecl *func) const;
2238+
2239+
public:
2240+
// Separate caching.
2241+
bool isCached() const { return true; }
2242+
llvm::Optional<Type> getCachedResult() const;
2243+
void cacheResult(Type value) const;
2244+
};
2245+
22252246
/// Determines the result type of a function or element type of a subscript.
22262247
class ResultTypeRequest
22272248
: public SimpleRequest<ResultTypeRequest,

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,8 @@ SWIFT_REQUEST(TypeChecker, NeedsNewVTableEntryRequest,
346346
bool(AbstractFunctionDecl *), SeparatelyCached, NoLocationInfo)
347347
SWIFT_REQUEST(TypeChecker, ParamSpecifierRequest,
348348
ParamDecl::Specifier(ParamDecl *), SeparatelyCached, NoLocationInfo)
349+
SWIFT_REQUEST(TypeChecker, ThrownTypeRequest,
350+
Type(AbstractFunctionDecl *), SeparatelyCached, NoLocationInfo)
349351
SWIFT_REQUEST(TypeChecker, ResultTypeRequest,
350352
Type(ValueDecl *), SeparatelyCached, NoLocationInfo)
351353
SWIFT_REQUEST(TypeChecker, AreAllStoredPropertiesDefaultInitableRequest,

include/swift/AST/Types.h

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -407,13 +407,14 @@ class alignas(1 << TypeAlignInBits) TypeBase
407407

408408
SWIFT_INLINE_BITFIELD_EMPTY(ParenType, SugarType);
409409

410-
SWIFT_INLINE_BITFIELD_FULL(AnyFunctionType, TypeBase, NumAFTExtInfoBits+1+1+1+16,
410+
SWIFT_INLINE_BITFIELD_FULL(AnyFunctionType, TypeBase, NumAFTExtInfoBits+1+1+1+1+16,
411411
/// Extra information which affects how the function is called, like
412412
/// regparm and the calling convention.
413413
ExtInfoBits : NumAFTExtInfoBits,
414414
HasExtInfo : 1,
415415
HasClangTypeInfo : 1,
416416
HasGlobalActor : 1,
417+
HasThrownError : 1,
417418
: NumPadBits,
418419
NumParams : 16
419420
);
@@ -3319,6 +3320,8 @@ class AnyFunctionType : public TypeBase {
33193320
!Info.value().getClangTypeInfo().empty();
33203321
Bits.AnyFunctionType.HasGlobalActor =
33213322
!Info.value().getGlobalActor().isNull();
3323+
Bits.AnyFunctionType.HasThrownError =
3324+
!Info.value().getThrownError().isNull();
33223325
// The use of both assert() and static_assert() is intentional.
33233326
assert(Bits.AnyFunctionType.ExtInfoBits == Info.value().getBits() &&
33243327
"Bits were dropped!");
@@ -3330,6 +3333,7 @@ class AnyFunctionType : public TypeBase {
33303333
Bits.AnyFunctionType.HasClangTypeInfo = false;
33313334
Bits.AnyFunctionType.ExtInfoBits = 0;
33323335
Bits.AnyFunctionType.HasGlobalActor = false;
3336+
Bits.AnyFunctionType.HasThrownError = false;
33333337
}
33343338
Bits.AnyFunctionType.NumParams = NumParams;
33353339
assert(Bits.AnyFunctionType.NumParams == NumParams && "Params dropped!");
@@ -3372,10 +3376,15 @@ class AnyFunctionType : public TypeBase {
33723376
return Bits.AnyFunctionType.HasGlobalActor;
33733377
}
33743378

3379+
bool hasThrownError() const {
3380+
return Bits.AnyFunctionType.HasThrownError;
3381+
}
3382+
33753383
ClangTypeInfo getClangTypeInfo() const;
33763384
ClangTypeInfo getCanonicalClangTypeInfo() const;
33773385

33783386
Type getGlobalActor() const;
3387+
Type getThrownError() const;
33793388

33803389
/// Returns true if the function type stores a Clang type that cannot
33813390
/// be derived from its Swift type. Returns false otherwise, including if
@@ -3400,23 +3409,14 @@ class AnyFunctionType : public TypeBase {
34003409
ExtInfo getExtInfo() const {
34013410
assert(hasExtInfo());
34023411
return ExtInfo(Bits.AnyFunctionType.ExtInfoBits, getClangTypeInfo(),
3403-
getGlobalActor());
3412+
getGlobalActor(), getThrownError());
34043413
}
34053414

34063415
/// Get the canonical ExtInfo for the function type.
34073416
///
34083417
/// The parameter useClangFunctionType is present only for staging purposes.
34093418
/// In the future, we will always use the canonical clang function type.
3410-
ExtInfo getCanonicalExtInfo(bool useClangFunctionType) const {
3411-
assert(hasExtInfo());
3412-
Type globalActor = getGlobalActor();
3413-
if (globalActor)
3414-
globalActor = globalActor->getCanonicalType();
3415-
return ExtInfo(Bits.AnyFunctionType.ExtInfoBits,
3416-
useClangFunctionType ? getCanonicalClangTypeInfo()
3417-
: ClangTypeInfo(),
3418-
globalActor);
3419-
}
3419+
ExtInfo getCanonicalExtInfo(bool useClangFunctionType) const;
34203420

34213421
bool hasSameExtInfoAs(const AnyFunctionType *otherFn);
34223422

@@ -3642,7 +3642,7 @@ class FunctionType final
36423642
}
36433643

36443644
size_t numTrailingObjects(OverloadToken<Type>) const {
3645-
return hasGlobalActor() ? 1 : 0;
3645+
return hasGlobalActor() + hasThrownError();
36463646
}
36473647

36483648
public:
@@ -3667,9 +3667,15 @@ class FunctionType final
36673667
Type getGlobalActor() const {
36683668
if (!hasGlobalActor())
36693669
return Type();
3670-
return *getTrailingObjects<Type>();
3670+
return getTrailingObjects<Type>()[0];
36713671
}
36723672

3673+
Type getThrownError() const {
3674+
if (!hasThrownError())
3675+
return Type();
3676+
return getTrailingObjects<Type>()[hasGlobalActor()];
3677+
}
3678+
36733679
void Profile(llvm::FoldingSetNodeID &ID) {
36743680
llvm::Optional<ExtInfo> info = llvm::None;
36753681
if (hasExtInfo())
@@ -3774,7 +3780,7 @@ class GenericFunctionType final : public AnyFunctionType,
37743780
}
37753781

37763782
size_t numTrailingObjects(OverloadToken<Type>) const {
3777-
return hasGlobalActor() ? 1 : 0;
3783+
return hasGlobalActor() + hasThrownError();
37783784
}
37793785

37803786
/// Construct a new generic function type.
@@ -3796,9 +3802,15 @@ class GenericFunctionType final : public AnyFunctionType,
37963802
Type getGlobalActor() const {
37973803
if (!hasGlobalActor())
37983804
return Type();
3799-
return *getTrailingObjects<Type>();
3805+
return getTrailingObjects<Type>()[0];
38003806
}
38013807

3808+
Type getThrownError() const {
3809+
if (!hasThrownError())
3810+
return Type();
3811+
return getTrailingObjects<Type>()[hasGlobalActor()];
3812+
}
3813+
38023814
/// Retrieve the generic signature of this function type.
38033815
GenericSignature getGenericSignature() const {
38043816
return Signature;

include/swift/Basic/Features.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,9 +235,13 @@ EXPERIMENTAL_FEATURE(RawLayout, true)
235235
/// Enables the "embedded" swift mode (no runtime).
236236
EXPERIMENTAL_FEATURE(Embedded, true)
237237

238+
238239
/// Enables noncopyable generics
239240
EXPERIMENTAL_FEATURE(NoncopyableGenerics, false)
240241

242+
/// Enables typed throws.
243+
EXPERIMENTAL_FEATURE(TypedThrows, true)
244+
241245
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
242246
#undef EXPERIMENTAL_FEATURE
243247
#undef UPCOMING_FEATURE

0 commit comments

Comments
 (0)