Skip to content

Commit b0fb03d

Browse files
committed
Create a uniform representation for function type isolation.
Not quite NFC because apparently the representation bleeds into what's accepted in some situations where we're supposed to be warning about conflicts and then making an arbitrary choice. But what we're doing is nonsense, so we definitely need to break behavior here. This is setting up for isolated(any) and isolated(caller). I tried to keep that out of the patch as much as possible, though.
1 parent 991a6de commit b0fb03d

25 files changed

+448
-153
lines changed

include/swift/AST/ASTDemangler.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ class ASTBuilder {
143143

144144
Type createFunctionType(
145145
ArrayRef<Demangle::FunctionParam<Type>> params,
146-
Type output, FunctionTypeFlags flags,
146+
Type output, FunctionTypeFlags flags, ExtendedFunctionTypeFlags extFlags,
147147
FunctionMetadataDifferentiabilityKind diffKind, Type globalActor,
148148
Type thrownError);
149149

include/swift/AST/ExtInfo.h

Lines changed: 138 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,78 @@ enum class SILFunctionTypeRepresentation : uint8_t;
4747

4848
namespace swift {
4949

50+
/// The formal isolation of a function type.
51+
class FunctionTypeIsolation {
52+
public:
53+
enum class Kind : uint8_t {
54+
/// The function is not isolated.
55+
NonIsolated,
56+
57+
/// The function is isolated to a global actor.
58+
GlobalActor,
59+
60+
/// The function has an isolated parameter; which one is indicated in
61+
/// the parameter list.
62+
Parameter,
63+
64+
/// The function is dynamically isolated.
65+
Dynamic,
66+
};
67+
68+
static constexpr size_t NumBits = 3; // future-proof this slightly
69+
static constexpr size_t Mask = (1 << NumBits) - 1;
70+
71+
private:
72+
llvm::PointerIntPair<Type, NumBits, Kind> value;
73+
74+
FunctionTypeIsolation(Kind kind, Type type = Type()) : value(type, kind) {}
75+
76+
public:
77+
static FunctionTypeIsolation forNonIsolated() {
78+
return { Kind::NonIsolated };
79+
}
80+
static FunctionTypeIsolation forGlobalActor(Type type) {
81+
assert(type && "creating global actor isolation without an actor type");
82+
return { Kind::GlobalActor, type };
83+
}
84+
static FunctionTypeIsolation forParameter() {
85+
return { Kind::Parameter };
86+
}
87+
static FunctionTypeIsolation forDynamic() {
88+
return { Kind::Dynamic };
89+
}
90+
91+
Kind getKind() const { return value.getInt(); }
92+
bool isNonIsolated() const {
93+
return getKind() == Kind::NonIsolated;
94+
}
95+
bool isGlobalActor() const {
96+
return getKind() == Kind::GlobalActor;
97+
}
98+
Type getGlobalActorType() const {
99+
assert(getKind() == Kind::GlobalActor);
100+
return value.getPointer();
101+
}
102+
bool isParameter() const {
103+
return getKind() == Kind::Parameter;
104+
}
105+
bool isDynamic() const {
106+
return getKind() == Kind::Dynamic;
107+
}
108+
109+
// The opaque accessors below are just for the benefit of ExtInfoBuilder,
110+
// which finds it convenient to break down the type separately. Normal
111+
// clients should use the accessors above.
112+
113+
Type getOpaqueType() const {
114+
return value.getPointer();
115+
}
116+
117+
static FunctionTypeIsolation fromOpaqueValues(Kind kind, Type type) {
118+
return FunctionTypeIsolation(kind, type);
119+
}
120+
};
121+
50122
// MARK: - ClangTypeInfo
51123
/// Wrapper class for storing a clang::Type in an (AST|SIL)ExtInfo.
52124
class ClangTypeInfo {
@@ -373,20 +445,24 @@ class ASTExtInfoBuilder {
373445
// If bits are added or removed, then TypeBase::NumAFTExtInfoBits
374446
// and NumMaskBits must be updated, and they must match.
375447
//
376-
// |representation|noEscape|concurrent|async|throws|differentiability|
377-
// | 0 .. 3 | 4 | 5 | 6 | 7 | 8 .. 10 |
448+
// |representation|noEscape|concurrent|async|throws|isolation|differentiability|
449+
// | 0 .. 3 | 4 | 5 | 6 | 7 | 8 .. 10 | 11 .. 13 |
378450
//
379451
enum : unsigned {
380452
RepresentationMask = 0xF << 0,
381453
NoEscapeMask = 1 << 4,
382454
SendableMask = 1 << 5,
383455
AsyncMask = 1 << 6,
384456
ThrowsMask = 1 << 7,
385-
DifferentiabilityMaskOffset = 8,
457+
IsolationMaskOffset = 8,
458+
IsolationMask = 0x7 << IsolationMaskOffset,
459+
DifferentiabilityMaskOffset = 11,
386460
DifferentiabilityMask = 0x7 << DifferentiabilityMaskOffset,
387-
NumMaskBits = 11
461+
NumMaskBits = 14
388462
};
389463

464+
static_assert(FunctionTypeIsolation::Mask == 0x7, "update mask manually");
465+
390466
unsigned bits; // Naturally sized for speed.
391467

392468
ClangTypeInfo clangTypeInfo;
@@ -403,33 +479,39 @@ class ASTExtInfoBuilder {
403479
LifetimeDependenceInfo lifetimeDependenceInfo)
404480
: bits(bits), clangTypeInfo(clangTypeInfo), globalActor(globalActor),
405481
thrownError(thrownError),
406-
lifetimeDependenceInfo(lifetimeDependenceInfo) {}
482+
lifetimeDependenceInfo(lifetimeDependenceInfo) {
483+
assert(isThrowing() || !thrownError);
484+
assert(hasGlobalActorFromBits(bits) == !globalActor.isNull());
485+
}
407486

408487
public:
409488
/// An ExtInfoBuilder for a typical Swift function: @convention(swift),
410489
/// @escaping, non-throwing, non-differentiable.
411490
ASTExtInfoBuilder()
412491
: ASTExtInfoBuilder(Representation::Swift, false, false, Type(),
413492
DifferentiabilityKind::NonDifferentiable, nullptr,
414-
Type(), LifetimeDependenceInfo()) {}
493+
FunctionTypeIsolation::forNonIsolated(),
494+
LifetimeDependenceInfo()) {}
415495

416496
// Constructor for polymorphic type.
417497
ASTExtInfoBuilder(Representation rep, bool throws, Type thrownError)
418498
: ASTExtInfoBuilder(rep, false, throws, thrownError,
419499
DifferentiabilityKind::NonDifferentiable, nullptr,
420-
Type(), LifetimeDependenceInfo()) {}
500+
FunctionTypeIsolation::forNonIsolated(),
501+
LifetimeDependenceInfo()) {}
421502

422503
// Constructor with no defaults.
423504
ASTExtInfoBuilder(Representation rep, bool isNoEscape, bool throws,
424505
Type thrownError, DifferentiabilityKind diffKind,
425-
const clang::Type *type, Type globalActor,
506+
const clang::Type *type, FunctionTypeIsolation isolation,
426507
LifetimeDependenceInfo lifetimeDependenceInfo)
427508
: ASTExtInfoBuilder(
428509
((unsigned)rep) | (isNoEscape ? NoEscapeMask : 0) |
429510
(throws ? ThrowsMask : 0) |
430511
(((unsigned)diffKind << DifferentiabilityMaskOffset) &
431-
DifferentiabilityMask),
432-
ClangTypeInfo(type), globalActor, thrownError,
512+
DifferentiabilityMask) |
513+
(unsigned(isolation.getKind()) << IsolationMaskOffset),
514+
ClangTypeInfo(type), isolation.getOpaqueType(), thrownError,
433515
lifetimeDependenceInfo) {}
434516

435517
void checkInvariants() const;
@@ -474,6 +556,26 @@ class ASTExtInfoBuilder {
474556
return lifetimeDependenceInfo;
475557
}
476558

559+
FunctionTypeIsolation::Kind getIsolationKind() const {
560+
return getIsolationKindFromBits(bits);
561+
}
562+
static FunctionTypeIsolation::Kind getIsolationKindFromBits(unsigned bits) {
563+
return FunctionTypeIsolation::Kind(
564+
(bits & IsolationMask) >> IsolationMaskOffset);
565+
}
566+
bool isDynamicallyIsolated() const {
567+
return getIsolationKind() == FunctionTypeIsolation::Kind::Dynamic;
568+
}
569+
static bool hasGlobalActorFromBits(unsigned bits) {
570+
return getIsolationKindFromBits(bits)
571+
== FunctionTypeIsolation::Kind::GlobalActor;
572+
}
573+
574+
FunctionTypeIsolation getIsolation() const {
575+
return FunctionTypeIsolation::fromOpaqueValues(getIsolationKind(),
576+
globalActor);
577+
}
578+
477579
constexpr bool hasSelfParam() const {
478580
switch (getSILRepresentation()) {
479581
case SILFunctionTypeRepresentation::Thick:
@@ -529,6 +631,7 @@ class ASTExtInfoBuilder {
529631
}
530632
[[nodiscard]]
531633
ASTExtInfoBuilder withThrows(bool throws, Type thrownError) const {
634+
assert(throws || !thrownError);
532635
return ASTExtInfoBuilder(
533636
throws ? (bits | ThrowsMask) : (bits & ~ThrowsMask), clangTypeInfo,
534637
globalActor, thrownError, lifetimeDependenceInfo);
@@ -566,15 +669,19 @@ class ASTExtInfoBuilder {
566669
}
567670

568671
[[nodiscard]]
569-
ASTExtInfoBuilder withGlobalActor(Type globalActor) const {
672+
ASTExtInfoBuilder withLifetimeDependenceInfo(
673+
LifetimeDependenceInfo lifetimeDependenceInfo) const {
570674
return ASTExtInfoBuilder(bits, clangTypeInfo, globalActor, thrownError,
571675
lifetimeDependenceInfo);
572676
}
573677

574-
[[nodiscard]] ASTExtInfoBuilder withLifetimeDependenceInfo(
575-
LifetimeDependenceInfo lifetimeDependenceInfo) const {
576-
return ASTExtInfoBuilder(bits, clangTypeInfo, globalActor, thrownError,
577-
lifetimeDependenceInfo);
678+
[[nodiscard]]
679+
ASTExtInfoBuilder withIsolation(FunctionTypeIsolation isolation) const {
680+
return ASTExtInfoBuilder(
681+
(bits & ~IsolationMask)
682+
| (unsigned(isolation.getKind()) << IsolationMaskOffset),
683+
clangTypeInfo, isolation.getOpaqueType(), thrownError,
684+
lifetimeDependenceInfo);
578685
}
579686

580687
bool isEqualTo(ASTExtInfoBuilder other, bool useClangTypes) const {
@@ -664,6 +771,8 @@ class ASTExtInfo {
664771
return builder.getLifetimeDependenceInfo();
665772
}
666773

774+
FunctionTypeIsolation getIsolation() const { return builder.getIsolation(); }
775+
667776
/// Helper method for changing the representation.
668777
///
669778
/// Prefer using \c ASTExtInfoBuilder::withRepresentation for chaining.
@@ -712,9 +821,22 @@ class ASTExtInfo {
712821
return builder.withAsync(async).build();
713822
}
714823

824+
[[nodiscard]]
825+
ASTExtInfo withIsolation(FunctionTypeIsolation isolation) const {
826+
return builder.withIsolation(isolation).build();
827+
}
828+
829+
[[nodiscard]]
830+
ASTExtInfo withoutIsolation() const {
831+
return builder.withIsolation(FunctionTypeIsolation::forNonIsolated())
832+
.build();
833+
}
834+
715835
[[nodiscard]]
716836
ASTExtInfo withGlobalActor(Type globalActor) const {
717-
return builder.withGlobalActor(globalActor).build();
837+
return builder.withIsolation(
838+
FunctionTypeIsolation::forGlobalActor(globalActor))
839+
.build();
718840
}
719841

720842
[[nodiscard]] ASTExtInfo withLifetimeDependenceInfo(

include/swift/AST/Types.h

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ class alignas(1 << TypeAlignInBits) TypeBase
384384
}
385385

386386
protected:
387-
enum { NumAFTExtInfoBits = 11 };
387+
enum { NumAFTExtInfoBits = 14 };
388388
enum { NumSILExtInfoBits = 13 };
389389

390390
// clang-format off
@@ -412,13 +412,12 @@ class alignas(1 << TypeAlignInBits) TypeBase
412412

413413
SWIFT_INLINE_BITFIELD_EMPTY(ParenType, SugarType);
414414

415-
SWIFT_INLINE_BITFIELD_FULL(AnyFunctionType, TypeBase, NumAFTExtInfoBits+1+1+1+1+1+16,
415+
SWIFT_INLINE_BITFIELD_FULL(AnyFunctionType, TypeBase, NumAFTExtInfoBits+1+1+1+1+16,
416416
/// Extra information which affects how the function is called, like
417417
/// regparm and the calling convention.
418418
ExtInfoBits : NumAFTExtInfoBits,
419419
HasExtInfo : 1,
420420
HasClangTypeInfo : 1,
421-
HasGlobalActor : 1,
422421
HasThrownError : 1,
423422
HasLifetimeDependenceInfo : 1,
424423
: NumPadBits,
@@ -3365,10 +3364,9 @@ class AnyFunctionType : public TypeBase {
33653364
Bits.AnyFunctionType.ExtInfoBits = Info.value().getBits();
33663365
Bits.AnyFunctionType.HasClangTypeInfo =
33673366
!Info.value().getClangTypeInfo().empty();
3368-
Bits.AnyFunctionType.HasGlobalActor =
3369-
!Info.value().getGlobalActor().isNull();
33703367
Bits.AnyFunctionType.HasThrownError =
33713368
!Info.value().getThrownError().isNull();
3369+
assert(!Bits.AnyFunctionType.HasThrownError || Info->isThrowing());
33723370
Bits.AnyFunctionType.HasLifetimeDependenceInfo =
33733371
!Info.value().getLifetimeDependenceInfo().empty();
33743372
// The use of both assert() and static_assert() is intentional.
@@ -3381,7 +3379,6 @@ class AnyFunctionType : public TypeBase {
33813379
Bits.AnyFunctionType.HasExtInfo = false;
33823380
Bits.AnyFunctionType.HasClangTypeInfo = false;
33833381
Bits.AnyFunctionType.ExtInfoBits = 0;
3384-
Bits.AnyFunctionType.HasGlobalActor = false;
33853382
Bits.AnyFunctionType.HasThrownError = false;
33863383
Bits.AnyFunctionType.HasLifetimeDependenceInfo = false;
33873384
}
@@ -3423,7 +3420,7 @@ class AnyFunctionType : public TypeBase {
34233420
}
34243421

34253422
bool hasGlobalActor() const {
3426-
return Bits.AnyFunctionType.HasGlobalActor;
3423+
return ExtInfoBuilder::hasGlobalActorFromBits(Bits.AnyFunctionType.ExtInfoBits);
34273424
}
34283425

34293426
bool hasThrownError() const {
@@ -3442,6 +3439,15 @@ class AnyFunctionType : public TypeBase {
34423439

34433440
LifetimeDependenceInfo getLifetimeDependenceInfo() const;
34443441

3442+
FunctionTypeIsolation getIsolation() const {
3443+
if (hasExtInfo())
3444+
return getExtInfo().getIsolation();
3445+
return FunctionTypeIsolation::forNonIsolated();
3446+
}
3447+
bool isDynamicallyIsolated() const {
3448+
return getIsolation().isDynamic();
3449+
}
3450+
34453451
/// Retrieve the "effective" thrown interface type, or llvm::None if
34463452
/// this function cannot throw.
34473453
///
@@ -3693,6 +3699,15 @@ END_CAN_TYPE_WRAPPER(AnyFunctionType, Type)
36933699
inline AnyFunctionType::CanYield AnyFunctionType::Yield::getCanonical() const {
36943700
return CanYield(getType()->getCanonicalType(), getFlags());
36953701
}
3702+
3703+
/// A convenience function to find out if any of the given parameters is
3704+
/// isolated.
3705+
///
3706+
/// You generally shouldn't need to call this when you're starting from a
3707+
/// function type; you can just check if the isolation on the type is
3708+
/// parameter isolation.
3709+
bool hasIsolatedParameter(ArrayRef<AnyFunctionType::Param> params);
3710+
36963711
/// FunctionType - A monomorphic function type, specified with an arrow.
36973712
///
36983713
/// For example:

include/swift/Demangling/TypeDecoder.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,7 @@ class TypeDecoder {
812812
Node->getNumChildren());
813813

814814
FunctionTypeFlags flags;
815+
ExtendedFunctionTypeFlags extFlags;
815816
if (Node->getKind() == NodeKind::ObjCBlock ||
816817
Node->getKind() == NodeKind::EscapingObjCBlock) {
817818
flags = flags.withConvention(FunctionMetadataConvention::Block);
@@ -847,6 +848,8 @@ class TypeDecoder {
847848
++firstChildIdx;
848849
}
849850

851+
// FIXME: other kinds of isolation
852+
850853
FunctionMetadataDifferentiabilityKind diffKind;
851854
if (Node->getChild(firstChildIdx)->getKind() ==
852855
NodeKind::DifferentiableFunctionType) {
@@ -895,6 +898,8 @@ class TypeDecoder {
895898

896899
thrownErrorType = thrownErrorResult.getType();
897900
++firstChildIdx;
901+
902+
extFlags = extFlags.withTypedThrows(true);
898903
}
899904

900905
bool isSendable = false;
@@ -941,8 +946,11 @@ class TypeDecoder {
941946
if (result.isError())
942947
return result;
943948

949+
if (extFlags != ExtendedFunctionTypeFlags())
950+
flags = flags.withExtendedFlags(true);
951+
944952
return Builder.createFunctionType(
945-
parameters, result.getType(), flags, diffKind, globalActorType,
953+
parameters, result.getType(), flags, extFlags, diffKind, globalActorType,
946954
thrownErrorType);
947955
}
948956
case NodeKind::ImplFunctionType: {

0 commit comments

Comments
 (0)