Skip to content

Commit 31146b7

Browse files
committed
Mangling: handle inverse requirements
1 parent 6abac66 commit 31146b7

21 files changed

+1029
-117
lines changed

docs/ABI/Mangling.rst

Lines changed: 99 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -467,8 +467,93 @@ An ``extension`` mangling is used whenever an entity's declaration context is
467467
an extension *and* the entity being extended is in a different module. In this
468468
case the extension's module is mangled first, followed by the entity being
469469
extended. If the extension and the extended entity are in the same module, the
470-
plain ``entity`` mangling is preferred. If the extension is constrained, the
471-
constraints on the extension are mangled in its generic signature.
470+
plain ``entity`` mangling is preferred, but not always used. An extension is
471+
considered "constrained" if it:
472+
473+
- Has any requirements not already satisfied by the extended nominal,
474+
excluding conformance requirements for invertible protocols.
475+
- Has any generic parameters with an inverse requirement.
476+
477+
Those requirements included in any of the above are included in the extension's
478+
generic signature. The reason for this additional complexity is that we do not
479+
mangle conformance req's for invertible protocols, only their absence.
480+
481+
::
482+
483+
struct S<A: ~Copyable, B: ~Copyable> {}
484+
485+
// An unconstrained extension.
486+
extension S {}
487+
488+
// Also an unconstrained extension, because there are no inverses to mangle.
489+
// This extension is exactly the same as the previous.
490+
extension S where A: Copyable, B: Copyable {}
491+
492+
// A constrained extension, because of the added requirement `B: P` that is
493+
// not already present in S.
494+
extension S where B: P {}
495+
496+
// A constrained extension, because of the absence of `A: Copyable`.
497+
// Despite also being absent in `S`, absences of invertible protocols
498+
// are always mangled.
499+
extension S where A: ~Copyable {}
500+
501+
As a consequence of the fact that some entities, like computed properties, rely
502+
503+
FIXME
504+
505+
506+
these rules for extensions, if the outermost type
507+
declaration (or extension) in the context has any inverses, then extension
508+
mangling is used. This strategy is used to ensure that moving a declaration
509+
between a nominal type and one of its extensions does not cause an ABI break if
510+
the generic signature of the entity is equivalent in both circumstances.
511+
For example:
512+
513+
::
514+
515+
struct R<A: ~Copyable> {
516+
func f1() {} // uses extension mangling, just like `f3`
517+
518+
func f2() where A: Copyable {}
519+
}
520+
521+
extension R where A: ~Copyable {
522+
func f3() {}
523+
524+
func f4() where A: Copyable {} // uses entity mangling, just like `f2`
525+
}
526+
527+
extension R where A: Copyable {
528+
// 'f5' is mangled equivalent to 'f2' and 'f4' modulo its identifier.
529+
func f5() {}
530+
}
531+
532+
For intermediate nested types, i.e., those between the top level and the entity,
533+
any inverses that remain in at the signature of the entity are mangled into
534+
that entity's generic signature:
535+
536+
::
537+
538+
struct X<A: ~Copyable> {
539+
struct Y<B: ~Copyable> {
540+
// 'g1' uses 'entity' context mangling with and has no mangled signatures.
541+
func g1() where A: Copyable, B: Copyable {}
542+
543+
// 'g2' uses 'entity' context mangling. The requirement `B: ~Copyable` is
544+
//mangled into the generic signature for 'g2'.
545+
func g2() where A: Copyable {}
546+
547+
// 'g3' uses extension mangling with generic signature 'A: ~Copyable'.
548+
// The mangled generic signature of 'g3' is empty.
549+
func g3() where B: Copyable {}
550+
551+
// 'g4' uses extension mangling with generic signature 'A: ~Copyable'.
552+
// The mangled generic signature of 'g4' contains 'B: ~Copyable'.
553+
func g4() {}
554+
}
555+
}
556+
472557

473558
When mangling the context of a local entity within a constructor or
474559
destructor, the non-allocating or non-deallocating variant is used.
@@ -680,12 +765,14 @@ Types
680765
METATYPE-REPR ::= 'T' // Thick metatype representation
681766
METATYPE-REPR ::= 'o' // ObjC metatype representation
682767

768+
existential-layout ::= protocol-list 'p' // existential layout
769+
existential-layout ::= protocol-list superclass 'Xc' // existential layout with superclass
770+
existential-layout ::= protocol-list 'Xl' // existential layout with AnyObject
771+
683772
type ::= associated-type
684773
type ::= any-generic-type
685-
type ::= protocol-list 'p' // existential type
686-
type ::= protocol-list superclass 'Xc' // existential type with superclass
687-
type ::= protocol-list 'Xl' // existential type with AnyObject
688-
type ::= protocol-list requirement* '_' 'XP' // constrained existential type
774+
type ::= existential-layout // existential type
775+
type ::= existential-layout requirement '_' requirement* 'XP' // constrained existential type
689776
type ::= type-list 't' // tuple
690777
type ::= type generic-signature 'u' // generic type
691778
type ::= 'x' // generic param, depth=0, idx=0
@@ -925,13 +1012,19 @@ now codified into the ABI; the index 0 is therefore reserved.
9251012

9261013
generic-param-pack-marker ::= 'Rv' GENERIC_PARAM-INDEX // generic parameter pack marker
9271014

1015+
INVERTIBLE-KIND ::= 'c' // Copyable
1016+
INVERTIBLE-KIND ::= 'e' // Escapable
1017+
9281018
GENERIC-PARAM-COUNT ::= 'z' // zero parameters
9291019
GENERIC-PARAM-COUNT ::= INDEX // N+1 parameters
9301020

9311021
requirement ::= protocol 'R' GENERIC-PARAM-INDEX // protocol requirement
9321022
requirement ::= protocol assoc-type-name 'Rp' GENERIC-PARAM-INDEX // protocol requirement on associated type
9331023
requirement ::= protocol assoc-type-list 'RP' GENERIC-PARAM-INDEX // protocol requirement on associated type at depth
9341024
requirement ::= protocol substitution 'RQ' // protocol requirement with substitution
1025+
#if SWIFT_RUNTIME_VERSION >= 6.0
1026+
requirement ::= 'Ri' INVERTIBLE-KIND GENERIC-PARAM-INDEX // inverse requirement
1027+
#endif
9351028
requirement ::= type 'Rb' GENERIC-PARAM-INDEX // base class requirement
9361029
requirement ::= type assoc-type-name 'Rc' GENERIC-PARAM-INDEX // base class requirement on associated type
9371030
requirement ::= type assoc-type-list 'RC' GENERIC-PARAM-INDEX // base class requirement on associated type at depth

include/swift/AST/ASTMangler.h

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,22 @@ class ASTMangler : public Mangler {
7272
/// If enabled, marker protocols can be encoded in the mangled name.
7373
bool AllowMarkerProtocols = true;
7474

75+
/// If enabled, inverses will not be mangled into generic signatures.
76+
bool AllowInverses = true;
77+
7578
/// If enabled, declarations annotated with @_originallyDefinedIn are mangled
7679
/// as if they're part of their original module. Disabled for debug mangling,
7780
/// because lldb wants to find declarations in the modules they're currently
7881
/// defined in.
7982
bool RespectOriginallyDefinedIn = true;
8083

84+
// Represents the innermost context of the entity whose context was appended.
85+
const DeclContext *baseContext = nullptr;
86+
87+
// Records the depth i such that inverse requirements for generic parameters
88+
// of depth <= i were already mangled.
89+
std::optional<unsigned> inversesAlreadyMangledDepth;
90+
8191
public:
8292
class SymbolicReferent {
8393
public:
@@ -392,6 +402,8 @@ class ASTMangler : public Mangler {
392402

393403
protected:
394404

405+
void beginManglingWithoutPrefix();
406+
395407
void appendSymbolKind(SymbolKind SKind);
396408

397409
void appendType(Type type, GenericSignature sig,
@@ -451,11 +463,16 @@ class ASTMangler : public Mangler {
451463
const ValueDecl *forDecl);
452464

453465
void appendContextOf(const ValueDecl *decl);
466+
void appendContextualInverses(GenericSignature contextSig,
467+
const ModuleDecl *module,
468+
StringRef useModuleName);
454469

455470
void appendContext(const DeclContext *ctx, StringRef useModuleName);
456471

457472
void appendModule(const ModuleDecl *module, StringRef useModuleName);
458473

474+
void appendExtension(const ExtensionDecl *ext, StringRef useModuleName);
475+
459476
void appendProtocolName(const ProtocolDecl *protocol,
460477
bool allowStandardSubstitution = true);
461478

@@ -503,6 +520,17 @@ class ASTMangler : public Mangler {
503520
GenericSignature sig,
504521
const ValueDecl *forDecl = nullptr);
505522

523+
struct GenericSignatureParts {
524+
ArrayRef<CanGenericTypeParamType> params;
525+
unsigned initialParamDepth = 0;
526+
unsigned inversesDepth = 0;
527+
SmallVector<Requirement, 2> requirements;
528+
SmallVector<InverseRequirement, 2> inverses;
529+
bool isNull() const; // Is there anything to mangle?
530+
bool hasRequirements() const; // Are there any requirements to mangle?
531+
void clear();
532+
};
533+
506534
/// Append a generic signature to the mangling.
507535
///
508536
/// \param sig The generic signature.
@@ -527,10 +555,22 @@ class ASTMangler : public Mangler {
527555
void appendRequirement(const Requirement &reqt, GenericSignature sig,
528556
bool lhsBaseIsProtocolSelf = false);
529557

558+
/// Append an inverse requirement into the mangling.
559+
///
560+
/// Instead of mangling the presence of an invertible protocol, we mangle
561+
/// their absence, which is what an inverse represents.
562+
///
563+
/// \param req The inverse requirement to mangle.
564+
void appendInverseRequirement(const InverseRequirement &req,
565+
GenericSignature sig,
566+
bool lhsBaseIsProtocolSelf = false);
567+
568+
void gatherGenericSignatureParts(GenericSignature sig,
569+
GenericSignature contextSig,
570+
GenericSignatureParts &parts);
571+
530572
void appendGenericSignatureParts(GenericSignature sig,
531-
ArrayRef<CanTypeWrapper<GenericTypeParamType>> params,
532-
unsigned initialParamDepth,
533-
ArrayRef<Requirement> requirements);
573+
GenericSignatureParts const& parts);
534574

535575
DependentMemberType *dropProtocolFromAssociatedType(DependentMemberType *dmt,
536576
GenericSignature sig);

include/swift/AST/Decl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1856,6 +1856,10 @@ class ExtensionDecl final : public GenericContext, public Decl,
18561856
/// resiliently moved into the original protocol itself.
18571857
bool isEquivalentToExtendedContext() const;
18581858

1859+
/// Determine whether this extension context is in the same defining module as
1860+
/// the original nominal type context.
1861+
bool isInSameDefiningModule() const;
1862+
18591863
/// Returns the name of the category specified by the \c \@_objcImplementation
18601864
/// attribute, or \c None if the name is invalid or
18611865
/// \c isObjCImplementation() is false.

include/swift/AST/DeclAttr.def

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,10 @@ SIMPLE_DECL_ATTR(_noObjCBridging, NoObjCBridging,
488488
DECL_ATTR(_distributedThunkTarget, DistributedThunkTarget,
489489
OnAbstractFunction | UserInaccessible | ABIStableToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove,
490490
156)
491-
LAST_DECL_ATTR(DistributedThunkTarget)
491+
SIMPLE_DECL_ATTR(_preInverseGenerics, PreInverseGenerics,
492+
OnAbstractFunction | OnSubscript | OnVar | UserInaccessible | ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove,
493+
157)
494+
LAST_DECL_ATTR(PreInverseGenerics)
492495

493496
#undef DECL_ATTR_ALIAS
494497
#undef CONTEXTUAL_DECL_ATTR_ALIAS

include/swift/AST/Requirement.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ class Requirement {
145145
llvm_unreachable("Unhandled RequirementKind in switch");
146146
}
147147

148+
friend bool operator!=(const Requirement &lhs,
149+
const Requirement &rhs) {
150+
return !(lhs == rhs);
151+
}
152+
148153
/// Whether this requirement's types contain ErrorTypes.
149154
bool hasError() const;
150155

@@ -257,6 +262,9 @@ struct InverseRequirement {
257262

258263
InvertibleProtocolKind getKind() const;
259264

265+
/// Linear order on inverse requirements in a generic signature.
266+
int compare(const InverseRequirement &other) const;
267+
260268
/// Appends additional requirements corresponding to defaults for the given
261269
/// generic parameters.
262270
static void expandDefaults(ASTContext &ctx,

include/swift/AST/Types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6007,6 +6007,7 @@ class ProtocolCompositionType final : public TypeBase,
60076007
}
60086008

60096009
InvertibleProtocolSet getInverses() const { return Inverses; }
6010+
bool hasInverse() const { return !Inverses.empty(); }
60106011

60116012
void Profile(llvm::FoldingSetNodeID &ID) {
60126013
Profile(ID, getMembers(), getInverses(), hasExplicitAnyObject());

include/swift/Demangling/DemangleNodes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,5 +393,7 @@ NODE(OutlinedAssignWithTakeNoValueWitness)
393393
NODE(OutlinedAssignWithCopyNoValueWitness)
394394
NODE(OutlinedDestroyNoValueWitness)
395395

396+
NODE(DependentGenericInverseConformanceRequirement)
397+
396398
#undef CONTEXT_NODE
397399
#undef NODE

include/swift/Demangling/TypeDecoder.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,8 +448,14 @@ void decodeRequirement(NodePointer node,
448448
child->getChild(1), /*forRequirement=*/false);
449449
if (!constraintType)
450450
return;
451+
} else if (child->getKind() ==
452+
Demangle::Node::Kind::DependentGenericInverseConformanceRequirement) {
453+
// FIXME(kavon): this is unimplemented! We should build a PCT here with
454+
// the inverse in it.
455+
return;
451456
}
452457

458+
453459
switch (child->getKind()) {
454460
case Demangle::Node::Kind::DependentGenericConformanceRequirement: {
455461
requirements.push_back(BuiltRequirement(

0 commit comments

Comments
 (0)