Skip to content

Commit 1e5659e

Browse files
authored
Merge pull request #72709 from DougGregor/dynamic-invertible-protocols-6.0
[6.0] Metadata and runtime support for invertible protocol requirements
2 parents f7d5395 + 5e3604b commit 1e5659e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1712
-368
lines changed

docs/ABI/Mangling.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,9 +1011,6 @@ now codified into the ABI; the index 0 is therefore reserved.
10111011

10121012
generic-param-pack-marker ::= 'Rv' GENERIC_PARAM-INDEX // generic parameter pack marker
10131013

1014-
INVERTIBLE-KIND ::= 'c' // Copyable
1015-
INVERTIBLE-KIND ::= 'e' // Escapable
1016-
10171014
GENERIC-PARAM-COUNT ::= 'z' // zero parameters
10181015
GENERIC-PARAM-COUNT ::= INDEX // N+1 parameters
10191016

@@ -1022,7 +1019,10 @@ now codified into the ABI; the index 0 is therefore reserved.
10221019
requirement ::= protocol assoc-type-list 'RP' GENERIC-PARAM-INDEX // protocol requirement on associated type at depth
10231020
requirement ::= protocol substitution 'RQ' // protocol requirement with substitution
10241021
#if SWIFT_RUNTIME_VERSION >= 6.0
1025-
requirement ::= 'Ri' INVERTIBLE-KIND GENERIC-PARAM-INDEX // inverse requirement
1022+
requirement ::= 'Ri' INDEX GENERIC-PARAM-INDEX // inverse requirement on generic parameter where INDEX is the bit number
1023+
requirement ::= substitution 'RI' INDEX // inverse requirement with substitution
1024+
requirement ::= assoc-type-name 'Rj' INDEX GENERIC-PARAM-INDEX // inverse requirement on associated type
1025+
requirement ::= assoc-type-list 'RJ' INDEX GENERIC-PARAM-INDEX // inverse requirement on associated type at depth
10261026
#endif
10271027
requirement ::= type 'Rb' GENERIC-PARAM-INDEX // base class requirement
10281028
requirement ::= type assoc-type-name 'Rc' GENERIC-PARAM-INDEX // base class requirement on associated type

include/swift/ABI/GenericContext.h

Lines changed: 166 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "swift/ABI/TargetLayout.h"
2222
#include "swift/ABI/MetadataValues.h"
2323
#include "swift/ABI/MetadataRef.h"
24+
#include "swift/ABI/InvertibleProtocols.h"
2425
#include "swift/ABI/TrailingObjects.h"
2526
#include "swift/Demangling/Demangle.h"
2627

@@ -103,6 +104,10 @@ struct TargetGenericContextDescriptorHeader {
103104
bool hasArguments() const {
104105
return getNumArguments() > 0;
105106
}
107+
108+
bool hasConditionalInvertedProtocols() const {
109+
return Flags.hasConditionalInvertedProtocols();
110+
}
106111
};
107112
using GenericContextDescriptorHeader =
108113
TargetGenericContextDescriptorHeader<InProcess>;
@@ -137,6 +142,20 @@ class TargetGenericRequirementDescriptor {
137142
///
138143
/// Only valid if the requirement has Layout kind.
139144
GenericRequirementLayoutKind Layout;
145+
146+
/// The set of invertible protocols whose check is disabled, along
147+
/// with the index of the generic parameter to which this applies.
148+
///
149+
/// The index is technically redundant with the subject type, but its
150+
/// storage is effectively free because this union is 32 bits anyway. The
151+
/// index 0xFFFF is reserved for "not a generic parameter", in which case
152+
/// the constraints are on the subject type.
153+
///
154+
/// Only valid if the requirement has InvertedProtocols kind.
155+
struct {
156+
uint16_t GenericParamIndex;
157+
InvertibleProtocolSet Protocols;
158+
} InvertedProtocols;
140159
};
141160

142161
constexpr GenericRequirementFlags getFlags() const {
@@ -204,6 +223,18 @@ class TargetGenericRequirementDescriptor {
204223
return Layout;
205224
}
206225

226+
/// Retrieve the set of inverted protocols.
227+
InvertibleProtocolSet getInvertedProtocols() const {
228+
assert(getKind() == GenericRequirementKind::InvertedProtocols);
229+
return InvertedProtocols.Protocols;
230+
}
231+
232+
/// Retrieve the invertible protocol kind.
233+
uint16_t getInvertedProtocolsGenericParamIndex() const {
234+
assert(getKind() == GenericRequirementKind::InvertedProtocols);
235+
return InvertedProtocols.GenericParamIndex;
236+
}
237+
207238
/// Determine whether this generic requirement has a known kind.
208239
///
209240
/// \returns \c false for any future generic requirement kinds.
@@ -215,6 +246,7 @@ class TargetGenericRequirementDescriptor {
215246
case GenericRequirementKind::SameConformance:
216247
case GenericRequirementKind::SameType:
217248
case GenericRequirementKind::SameShape:
249+
case GenericRequirementKind::InvertedProtocols:
218250
return true;
219251
}
220252

@@ -266,6 +298,26 @@ struct GenericPackShapeDescriptor {
266298
uint16_t Unused;
267299
};
268300

301+
/// A count for the number of requirements for the number of requirements
302+
/// for a given conditional conformance to a invertible protocols.
303+
struct ConditionalInvertibleProtocolsRequirementCount {
304+
uint16_t count;
305+
};
306+
307+
/// A invertible protocol set used for the conditional conformances in a
308+
/// generic context.
309+
struct ConditionalInvertibleProtocolSet: InvertibleProtocolSet {
310+
using InvertibleProtocolSet::InvertibleProtocolSet;
311+
};
312+
313+
/// A generic requirement for describing a conditional conformance to a
314+
/// invertible protocol.
315+
///
316+
/// This type is equivalent to a `TargetGenericRequirementDescriptor`, and
317+
/// differs only because it needs to occur alongside
318+
template<typename Runtime>
319+
struct TargetConditionalInvertibleProtocolRequirement: TargetGenericRequirementDescriptor<Runtime> { };
320+
269321
/// An array of generic parameter descriptors, all
270322
/// GenericParamDescriptor::implicit(), which is by far
271323
/// the most common case. Some generic context storage can
@@ -306,7 +358,8 @@ class RuntimeGenericSignature {
306358

307359
public:
308360
RuntimeGenericSignature()
309-
: Header{0, 0, 0, 0}, Params(nullptr), Requirements(nullptr),
361+
: Header{0, 0, 0, GenericContextDescriptorFlags(false, false)},
362+
Params(nullptr), Requirements(nullptr),
310363
PackShapeHeader{0, 0}, PackShapeDescriptors(nullptr) {}
311364

312365
RuntimeGenericSignature(const TargetGenericContextDescriptorHeader<Runtime> &header,
@@ -425,20 +478,27 @@ class TrailingGenericContextObjects<TargetSelf<Runtime>,
425478
TargetGenericRequirementDescriptor<Runtime>,
426479
GenericPackShapeHeader,
427480
GenericPackShapeDescriptor,
481+
ConditionalInvertibleProtocolSet,
482+
ConditionalInvertibleProtocolsRequirementCount,
483+
TargetConditionalInvertibleProtocolRequirement<Runtime>,
428484
FollowingTrailingObjects...>
429485
{
430486
protected:
431487
using Self = TargetSelf<Runtime>;
432488
using GenericContextHeaderType = TargetGenericContextHeaderType<Runtime>;
433489
using GenericRequirementDescriptor =
434490
TargetGenericRequirementDescriptor<Runtime>;
435-
491+
using GenericConditionalInvertibleProtocolRequirement =
492+
TargetConditionalInvertibleProtocolRequirement<Runtime>;
436493
using TrailingObjects = swift::ABI::TrailingObjects<Self,
437494
GenericContextHeaderType,
438495
GenericParamDescriptor,
439496
GenericRequirementDescriptor,
440497
GenericPackShapeHeader,
441498
GenericPackShapeDescriptor,
499+
ConditionalInvertibleProtocolSet,
500+
ConditionalInvertibleProtocolsRequirementCount,
501+
GenericConditionalInvertibleProtocolRequirement,
442502
FollowingTrailingObjects...>;
443503
friend TrailingObjects;
444504

@@ -467,7 +527,84 @@ class TrailingGenericContextObjects<TargetSelf<Runtime>,
467527
/// HeaderType ought to be convertible to GenericContextDescriptorHeader.
468528
return getFullGenericContextHeader();
469529
}
470-
530+
531+
bool hasConditionalInvertedProtocols() const {
532+
if (!asSelf()->isGeneric())
533+
return false;
534+
535+
return getGenericContextHeader().hasConditionalInvertedProtocols();
536+
}
537+
538+
const InvertibleProtocolSet &
539+
getConditionalInvertedProtocols() const {
540+
assert(hasConditionalInvertedProtocols());
541+
return *this->template
542+
getTrailingObjects<ConditionalInvertibleProtocolSet>();
543+
}
544+
545+
/// Retrieve the counts for # of conditional invertible protocols for each
546+
/// conditional conformance to a invertible protocol.
547+
///
548+
/// The counts are cumulative, so the first entry in the array is the
549+
/// number of requirements for the first conditional conformance. The
550+
/// second entry in the array is the number of requirements in the first
551+
/// and second conditional conformances. The last entry is, therefore, the
552+
/// total count of requirements in the structure.
553+
llvm::ArrayRef<ConditionalInvertibleProtocolsRequirementCount>
554+
getConditionalInvertibleProtocolRequirementCounts() const {
555+
if (!asSelf()->hasConditionalInvertedProtocols())
556+
return {};
557+
558+
return {
559+
this->template
560+
getTrailingObjects<ConditionalInvertibleProtocolsRequirementCount>(),
561+
getNumConditionalInvertibleProtocolsRequirementCounts()
562+
};
563+
}
564+
565+
/// Retrieve the array of requirements for conditional conformances to
566+
/// the ith conditional conformance to a invertible protocol.
567+
llvm::ArrayRef<GenericConditionalInvertibleProtocolRequirement>
568+
getConditionalInvertibleProtocolRequirementsAt(unsigned i) const {
569+
auto counts = getConditionalInvertibleProtocolRequirementCounts();
570+
assert(i < counts.size());
571+
572+
unsigned startIndex = (i == 0) ? 0 : counts[i-1].count;
573+
unsigned endIndex = counts[i].count;
574+
575+
auto basePtr =
576+
this->template
577+
getTrailingObjects<GenericConditionalInvertibleProtocolRequirement>();
578+
return { basePtr + startIndex, basePtr + endIndex };
579+
}
580+
581+
/// Retrieve the array of requirements for conditional conformances to
582+
/// the ith conditional conformance to a invertible protocol.
583+
llvm::ArrayRef<GenericConditionalInvertibleProtocolRequirement>
584+
getConditionalInvertibleProtocolRequirementsFor(
585+
InvertibleProtocolKind kind
586+
) const {
587+
if (!asSelf()->hasConditionalInvertedProtocols())
588+
return { };
589+
590+
auto conditionallyInverted = getConditionalInvertedProtocols();
591+
if (!conditionallyInverted.contains(kind))
592+
return { };
593+
594+
// Count the number of "set" bits up to (but not including) the
595+
// bit we're looking at.
596+
unsigned targetBit = static_cast<uint8_t>(kind);
597+
auto invertedBits = conditionallyInverted.rawBits();
598+
unsigned priorBits = 0;
599+
for (unsigned i = 0; i != targetBit; ++i) {
600+
if (invertedBits & 0x01)
601+
++priorBits;
602+
invertedBits = invertedBits >> 1;
603+
}
604+
605+
return getConditionalInvertibleProtocolRequirementsAt(priorBits);
606+
}
607+
471608
const TargetGenericContext<Runtime> *getGenericContext() const {
472609
if (!asSelf()->isGeneric())
473610
return nullptr;
@@ -549,6 +686,32 @@ class TrailingGenericContextObjects<TargetSelf<Runtime>,
549686
return getGenericPackShapeHeader().NumPacks;
550687
}
551688

689+
size_t numTrailingObjects(
690+
OverloadToken<ConditionalInvertibleProtocolSet>
691+
) const {
692+
return asSelf()->hasConditionalInvertedProtocols() ? 1 : 0;
693+
}
694+
695+
unsigned getNumConditionalInvertibleProtocolsRequirementCounts() const {
696+
if (!asSelf()->hasConditionalInvertedProtocols())
697+
return 0;
698+
699+
return countBitsUsed(getConditionalInvertedProtocols().rawBits());
700+
}
701+
702+
size_t numTrailingObjects(
703+
OverloadToken<ConditionalInvertibleProtocolsRequirementCount>
704+
) const {
705+
return getNumConditionalInvertibleProtocolsRequirementCounts();
706+
}
707+
708+
size_t numTrailingObjects(
709+
OverloadToken<GenericConditionalInvertibleProtocolRequirement>
710+
) const {
711+
auto counts = getConditionalInvertibleProtocolRequirementCounts();
712+
return counts.empty() ? 0 : counts.back().count;
713+
}
714+
552715
#if defined(_MSC_VER) && _MSC_VER < 1920
553716
#undef OverloadToken
554717
#endif
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//===--- InvertibleProtocols.def - invertible protocol meta -*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines macros used for macro-metaprogramming with ABI-defined
14+
// invertible protocols.
15+
//
16+
// The INVERTIBLE_PROTOCOL(Name, Bit) macro is used to specify each
17+
// each invertible protocol that's conceptually part of the ABI. The
18+
// arguments are:
19+
// Name: The name of the protocol, e.g., Copyable
20+
// Bit: The bit in the set bitset of invertible protocols that is used
21+
// to indicate this.
22+
//===----------------------------------------------------------------------===//
23+
24+
#ifndef INVERTIBLE_PROTOCOL
25+
# error Must define INVERTIBLE_PROTOCOL macro before including this file
26+
#endif
27+
28+
INVERTIBLE_PROTOCOL(Copyable, 0)
29+
INVERTIBLE_PROTOCOL(Escapable, 1)
30+
31+
#undef INVERTIBLE_PROTOCOL

0 commit comments

Comments
 (0)