Skip to content

Commit ba8819e

Browse files
committed
[Concurrent] Introduce concurrent function types.
Introduce `@concurrent` attribute on function types, including: * Parsing as a type attribute * (De-/re-/)mangling for concurrent function types * Implicit conversion from @Concurrent to non-@Concurrent - (De-)serialization for concurrent function types - AST printing and dumping support
1 parent ae7e1b5 commit ba8819e

36 files changed

+292
-61
lines changed

docs/ABI/Mangling.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,13 +556,14 @@ Types
556556
C-TYPE is mangled according to the Itanium ABI, and prefixed with the length.
557557
Non-ASCII identifiers are preserved as-is; we do not use Punycode.
558558

559-
function-signature ::= params-type params-type async? throws? // results and parameters
559+
function-signature ::= params-type params-type async? concurrent? throws? // results and parameters
560560

561561
params-type ::= type 'z'? 'h'? // tuple in case of multiple parameters or a single parameter with a single tuple type
562562
// with optional inout convention, shared convention. parameters don't have labels,
563563
// they are mangled separately as part of the entity.
564564
params-type ::= empty-list // shortcut for no parameters
565565

566+
concurrent ::= 'J' // @concurrent on function types
566567
async ::= 'Y' // 'async' annotation on function types
567568
throws ::= 'K' // 'throws' annotation on function types
568569

include/swift/ABI/Metadata.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,6 +1637,7 @@ struct TargetFunctionTypeMetadata : public TargetMetadata<Runtime> {
16371637
}
16381638
bool isAsync() const { return Flags.isAsync(); }
16391639
bool isThrowing() const { return Flags.isThrowing(); }
1640+
bool isConcurrent() const { return Flags.isConcurrent(); }
16401641
bool hasParameterFlags() const { return Flags.hasParameterFlags(); }
16411642
bool isEscaping() const { return Flags.isEscaping(); }
16421643

include/swift/ABI/MetadataValues.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,7 @@ class TargetFunctionTypeFlags {
779779
DifferentiableMask = 0x08000000U,
780780
LinearMask = 0x10000000U,
781781
AsyncMask = 0x20000000U,
782+
ConcurrentMask = 0x40000000U,
782783
};
783784
int_type Data;
784785

@@ -831,6 +832,13 @@ class TargetFunctionTypeFlags {
831832
(isEscaping ? EscapingMask : 0));
832833
}
833834

835+
constexpr TargetFunctionTypeFlags<int_type>
836+
withConcurrent(bool isConcurrent) const {
837+
return TargetFunctionTypeFlags<int_type>(
838+
(Data & ~ConcurrentMask) |
839+
(isConcurrent ? ConcurrentMask : 0));
840+
}
841+
834842
unsigned getNumParameters() const { return Data & NumParametersMask; }
835843

836844
FunctionMetadataConvention getConvention() const {
@@ -845,6 +853,10 @@ class TargetFunctionTypeFlags {
845853
return bool (Data & EscapingMask);
846854
}
847855

856+
bool isConcurrent() const {
857+
return bool (Data & ConcurrentMask);
858+
}
859+
848860
bool hasParameterFlags() const { return bool(Data & ParamFlagsMask); }
849861

850862
bool isDifferentiable() const {

include/swift/AST/Attr.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ TYPE_ATTR(escaping)
5454
TYPE_ATTR(differentiable)
5555
TYPE_ATTR(noDerivative)
5656
TYPE_ATTR(async)
57+
TYPE_ATTR(concurrent)
5758

5859
// SIL-specific attributes
5960
TYPE_ATTR(block_storage)

include/swift/AST/DiagnosticsSema.def

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3724,26 +3724,30 @@ NOTE(silence_debug_description_in_interpolation_segment_call,none,
37243724
"use 'String(describing:)' to silence this warning", ())
37253725

37263726
NOTE(noescape_parameter,none,
3727-
"parameter %0 is implicitly non-escaping",
3728-
(Identifier))
3727+
"parameter %1 is implicitly %select{non-escaping|non-concurrent}0",
3728+
(unsigned, Identifier))
37293729
NOTE(generic_parameters_always_escaping,none,
37303730
"generic parameters are always considered '@escaping'", ())
37313731

3732-
ERROR(passing_noescape_to_escaping,none,
3733-
"passing non-escaping parameter %0 to function expecting an @escaping closure",
3734-
(Identifier))
3732+
ERROR(passing_noattrfunc_to_attrfunc,none,
3733+
"passing %select{non-escaping|non-concurrent}0 parameter %1 to function "
3734+
"expecting %select{an @escaping|a @concurrent}0 closure",
3735+
(unsigned, Identifier))
37353736
ERROR(converting_noespace_param_to_generic_type,none,
37363737
"converting non-escaping parameter %0 to generic parameter %1 may allow it to escape",
37373738
(Identifier, Type))
3738-
ERROR(assigning_noescape_to_escaping,none,
3739-
"assigning non-escaping parameter %0 to an @escaping closure",
3740-
(Identifier))
3741-
ERROR(general_noescape_to_escaping,none,
3742-
"using non-escaping parameter %0 in a context expecting an @escaping closure",
3743-
(Identifier))
3744-
ERROR(converting_noescape_to_type,none,
3745-
"converting non-escaping value to %0 may allow it to escape",
3746-
(Type))
3739+
ERROR(assigning_noattrfunc_to_attrfunc,none,
3740+
"assigning %select{non-escaping|non-concurrent}0 parameter %1 to "
3741+
"%select{an @escaping|a @concurrent}0 closure",
3742+
(unsigned, Identifier))
3743+
ERROR(general_noattrfunc_to_attr,none,
3744+
"using %select{non-escaping|non-concurrent}0 parameter %1 in a context "
3745+
"expecting %select{an @escaping|a @concurrent}0 closure",
3746+
(unsigned, Identifier))
3747+
ERROR(converting_noattrfunc_to_type,none,
3748+
"converting %select{non-escaping|non-concurrent function}0 value to %1 "
3749+
"may %select{allow it to escape|introduce data races}0",
3750+
(unsigned, Type))
37473751

37483752
ERROR(capture_across_type_decl,none,
37493753
"%0 declaration cannot close over value %1 defined in outer scope",

include/swift/AST/ExtInfo.h

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -289,20 +289,21 @@ class ASTExtInfoBuilder {
289289
friend AnyFunctionType;
290290
friend ASTExtInfo;
291291

292-
// If bits are added or removed, then TypeBase::AnyFunctionTypeBits
292+
// If bits are added or removed, then TypeBase::NumAFTExtInfoBits
293293
// and NumMaskBits must be updated, and they must match.
294294
//
295-
// |representation|noEscape|async|throws|differentiability|
296-
// | 0 .. 3 | 4 | 5 | 6 | 7 .. 8 |
295+
// |representation|noEscape|concurrent|async|throws|differentiability|
296+
// | 0 .. 3 | 4 | 5 | 6 | 7 | 8 .. 9 |
297297
//
298298
enum : unsigned {
299299
RepresentationMask = 0xF << 0,
300300
NoEscapeMask = 1 << 4,
301-
AsyncMask = 1 << 5,
302-
ThrowsMask = 1 << 6,
303-
DifferentiabilityMaskOffset = 7,
301+
ConcurrentMask = 1 << 5,
302+
AsyncMask = 1 << 6,
303+
ThrowsMask = 1 << 7,
304+
DifferentiabilityMaskOffset = 8,
304305
DifferentiabilityMask = 0x3 << DifferentiabilityMaskOffset,
305-
NumMaskBits = 9
306+
NumMaskBits = 10
306307
};
307308

308309
unsigned bits; // Naturally sized for speed.
@@ -350,6 +351,8 @@ class ASTExtInfoBuilder {
350351

351352
constexpr bool isNoEscape() const { return bits & NoEscapeMask; }
352353

354+
constexpr bool isConcurrent() const { return bits & ConcurrentMask; }
355+
353356
constexpr bool isAsync() const { return bits & AsyncMask; }
354357

355358
constexpr bool isThrowing() const { return bits & ThrowsMask; }
@@ -407,6 +410,12 @@ class ASTExtInfoBuilder {
407410
clangTypeInfo);
408411
}
409412
LLVM_NODISCARD
413+
ASTExtInfoBuilder withConcurrent(bool concurrent = true) const {
414+
return ASTExtInfoBuilder(concurrent ? (bits | ConcurrentMask)
415+
: (bits & ~ConcurrentMask),
416+
clangTypeInfo);
417+
}
418+
LLVM_NODISCARD
410419
ASTExtInfoBuilder withAsync(bool async = true) const {
411420
return ASTExtInfoBuilder(async ? (bits | AsyncMask)
412421
: (bits & ~AsyncMask),
@@ -497,6 +506,8 @@ class ASTExtInfo {
497506

498507
constexpr bool isNoEscape() const { return builder.isNoEscape(); }
499508

509+
constexpr bool isConcurrent() const { return builder.isConcurrent(); }
510+
500511
constexpr bool isAsync() const { return builder.isAsync(); }
501512

502513
constexpr bool isThrowing() const { return builder.isThrowing(); }
@@ -529,6 +540,14 @@ class ASTExtInfo {
529540
return builder.withNoEscape(noEscape).build();
530541
}
531542

543+
/// Helper method for changing only the concurrent field.
544+
///
545+
/// Prefer using \c ASTExtInfoBuilder::withConcurrent for chaining.
546+
LLVM_NODISCARD
547+
ASTExtInfo withConcurrent(bool concurrent = true) const {
548+
return builder.withConcurrent(concurrent).build();
549+
}
550+
532551
/// Helper method for changing only the throws field.
533552
///
534553
/// Prefer using \c ASTExtInfoBuilder::withThrows for chaining.

include/swift/AST/TypeMatcher.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,9 @@ class TypeMatcher {
208208
if (firstFunc->isNoEscape() != secondFunc->isNoEscape())
209209
return mismatch(firstFunc.getPointer(), secondFunc, sugaredFirstType);
210210

211+
if (firstFunc->isConcurrent() != secondFunc->isConcurrent())
212+
return mismatch(firstFunc.getPointer(), secondFunc, sugaredFirstType);
213+
211214
auto sugaredFirstFunc = sugaredFirstType->castTo<AnyFunctionType>();
212215
if (firstFunc->getParams().size() != secondFunc->getParams().size())
213216
return mismatch(firstFunc.getPointer(), secondFunc, sugaredFirstFunc);

include/swift/AST/Types.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ class alignas(1 << TypeAlignInBits) TypeBase {
315315
}
316316

317317
protected:
318-
enum { NumAFTExtInfoBits = 9 };
318+
enum { NumAFTExtInfoBits = 10 };
319319
enum { NumSILExtInfoBits = 9 };
320320
union { uint64_t OpaqueBits;
321321

@@ -3145,6 +3145,10 @@ class AnyFunctionType : public TypeBase {
31453145
return getExtInfo().isNoEscape();
31463146
}
31473147

3148+
bool isConcurrent() const {
3149+
return getExtInfo().isConcurrent();
3150+
}
3151+
31483152
bool isAsync() const { return getExtInfo().isAsync(); }
31493153

31503154
bool isThrowing() const { return getExtInfo().isThrowing(); }

include/swift/Demangling/DemangleNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ NODE(EnumCase)
8585
NODE(ErrorType)
8686
NODE(EscapingAutoClosureType)
8787
NODE(NoEscapeFunctionType)
88+
NODE(ConcurrentFunctionType)
8889
NODE(ExistentialMetatype)
8990
CONTEXT_NODE(ExplicitClosure)
9091
CONTEXT_NODE(Extension)

include/swift/Demangling/TypeDecoder.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -645,14 +645,22 @@ class TypeDecoder {
645645
++firstChildIdx;
646646
}
647647

648+
bool isConcurrent = false;
649+
if (Node->getChild(firstChildIdx)->getKind()
650+
== NodeKind::ConcurrentFunctionType) {
651+
isConcurrent = true;
652+
++firstChildIdx;
653+
}
654+
648655
bool isAsync = false;
649656
if (Node->getChild(firstChildIdx)->getKind()
650657
== NodeKind::AsyncAnnotation) {
651658
isAsync = true;
652659
++firstChildIdx;
653660
}
654661

655-
flags = flags.withAsync(isAsync).withThrows(isThrow);
662+
flags = flags.withConcurrent(isConcurrent)
663+
.withAsync(isAsync).withThrows(isThrow);
656664

657665
if (Node->getNumChildren() < firstChildIdx + 2)
658666
return MAKE_NODE_TYPE_ERROR(Node,

0 commit comments

Comments
 (0)