Skip to content

Commit 0d19444

Browse files
committed
Mangling: handle inverse requirements
1 parent 19a5bb0 commit 0d19444

23 files changed

+1337
-186
lines changed

docs/ABI/Mangling.rst

Lines changed: 98 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -467,8 +467,92 @@ 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+
Some entities, like computed properties, rely on the generic signature in their
502+
`context`, so in order to disambiguate between those properties and
503+
those in a context where a generic type requires Copyable, which is not mangled,
504+
we have the following rule:
505+
506+
If the innermost type declaration for an entity has any inverses in its generic
507+
signature, then extension mangling is used. This strategy is used to ensure
508+
that moving a declaration between a nominal type and one of its extensions does
509+
not cause an ABI break if the generic signature of the entity is equivalent in
510+
both circumstances. For example:
511+
512+
::
513+
514+
struct R<A: ~Copyable> {
515+
func f1() {} // uses extension mangling, just like `f3`
516+
517+
func f2() where A: Copyable {}
518+
}
519+
520+
extension R where A: ~Copyable {
521+
func f3() {}
522+
523+
func f4() where A: Copyable {} // uses entity mangling, just like `f2`
524+
}
525+
526+
extension R where A: Copyable {
527+
// 'f5' is mangled equivalent to 'f2' and 'f4' modulo its identifier.
528+
func f5() {}
529+
}
530+
531+
For intermediate nested types, i.e., those between the top level and the entity,
532+
any inverses that remain in at the signature of the entity are mangled into
533+
that entity's generic signature:
534+
535+
::
536+
537+
struct X<A: ~Copyable> {
538+
struct Y<B: ~Copyable> {
539+
// 'g1' uses 'entity' context mangling with and has no mangled signatures.
540+
func g1() where A: Copyable, B: Copyable {}
541+
542+
// 'g2' uses 'entity' context mangling. The requirement `B: ~Copyable` is
543+
//mangled into the generic signature for 'g2'.
544+
func g2() where A: Copyable {}
545+
546+
// 'g3' uses extension mangling with generic signature 'A: ~Copyable'.
547+
// The mangled generic signature of 'g3' is empty.
548+
func g3() where B: Copyable {}
549+
550+
// 'g4' uses extension mangling with generic signature 'A: ~Copyable'.
551+
// The mangled generic signature of 'g4' contains 'B: ~Copyable'.
552+
func g4() {}
553+
}
554+
}
555+
472556

473557
When mangling the context of a local entity within a constructor or
474558
destructor, the non-allocating or non-deallocating variant is used.
@@ -680,12 +764,14 @@ Types
680764
METATYPE-REPR ::= 'T' // Thick metatype representation
681765
METATYPE-REPR ::= 'o' // ObjC metatype representation
682766

767+
existential-layout ::= protocol-list 'p' // existential layout
768+
existential-layout ::= protocol-list superclass 'Xc' // existential layout with superclass
769+
existential-layout ::= protocol-list 'Xl' // existential layout with AnyObject
770+
683771
type ::= associated-type
684772
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
773+
type ::= existential-layout // existential type
774+
type ::= existential-layout requirement '_' requirement* 'XP' // constrained existential type
689775
type ::= type-list 't' // tuple
690776
type ::= type generic-signature 'u' // generic type
691777
type ::= 'x' // generic param, depth=0, idx=0
@@ -925,13 +1011,19 @@ now codified into the ABI; the index 0 is therefore reserved.
9251011

9261012
generic-param-pack-marker ::= 'Rv' GENERIC_PARAM-INDEX // generic parameter pack marker
9271013

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

9311020
requirement ::= protocol 'R' GENERIC-PARAM-INDEX // protocol requirement
9321021
requirement ::= protocol assoc-type-name 'Rp' GENERIC-PARAM-INDEX // protocol requirement on associated type
9331022
requirement ::= protocol assoc-type-list 'RP' GENERIC-PARAM-INDEX // protocol requirement on associated type at depth
9341023
requirement ::= protocol substitution 'RQ' // protocol requirement with substitution
1024+
#if SWIFT_RUNTIME_VERSION >= 6.0
1025+
requirement ::= 'Ri' INVERTIBLE-KIND GENERIC-PARAM-INDEX // inverse requirement
1026+
#endif
9351027
requirement ::= type 'Rb' GENERIC-PARAM-INDEX // base class requirement
9361028
requirement ::= type assoc-type-name 'Rc' GENERIC-PARAM-INDEX // base class requirement on associated type
9371029
requirement ::= type assoc-type-list 'RC' GENERIC-PARAM-INDEX // base class requirement on associated type at depth

include/swift/AST/ASTMangler.h

Lines changed: 90 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ 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
@@ -450,16 +453,54 @@ class ASTMangler : public Mangler {
450453
GenericSignature sig,
451454
const ValueDecl *forDecl);
452455

453-
void appendContextOf(const ValueDecl *decl);
456+
// A "base entity" is a function, property, subscript, or any other
457+
// declaration that can appear in an extension.
458+
struct BaseEntitySignature {
459+
private:
460+
GenericSignature sig;
461+
bool innermostTypeDecl;
462+
bool extension;
463+
std::optional<unsigned> mangledDepth; // for inverses
464+
public:
465+
bool reachedInnermostTypeDecl() {
466+
bool answer = innermostTypeDecl;
467+
innermostTypeDecl = false;
468+
return answer;
469+
}
470+
bool reachedExtension() const { return extension; }
471+
void setReachedExtension() { assert(!extension); extension = true; }
472+
GenericSignature getSignature() const { return sig; }
473+
// The depth of the inverses mangled so far.
474+
std::optional<unsigned> getDepth() const { return mangledDepth; }
475+
void setDepth(unsigned depth) {
476+
assert(!mangledDepth || *mangledDepth <= depth);
477+
mangledDepth = depth;
478+
}
479+
BaseEntitySignature(const Decl *decl);
480+
};
481+
482+
void appendContextOf(const ValueDecl *decl, BaseEntitySignature &base);
483+
void appendContextualInverses(const GenericTypeDecl *contextDecl,
484+
BaseEntitySignature &base,
485+
const ModuleDecl *module,
486+
StringRef useModuleName);
454487

455-
void appendContext(const DeclContext *ctx, StringRef useModuleName);
488+
void appendContext(const DeclContext *ctx,
489+
BaseEntitySignature &base,
490+
StringRef useModuleName);
456491

457492
void appendModule(const ModuleDecl *module, StringRef useModuleName);
458493

494+
void appendExtension(const ExtensionDecl *ext,
495+
BaseEntitySignature &base,
496+
StringRef useModuleName);
497+
459498
void appendProtocolName(const ProtocolDecl *protocol,
460499
bool allowStandardSubstitution = true);
461500

462501
void appendAnyGenericType(const GenericTypeDecl *decl);
502+
void appendAnyGenericType(const GenericTypeDecl *decl,
503+
BaseEntitySignature &base);
463504

464505
enum FunctionManglingKind {
465506
NoFunctionMangling,
@@ -503,17 +544,42 @@ class ASTMangler : public Mangler {
503544
GenericSignature sig,
504545
const ValueDecl *forDecl = nullptr);
505546

547+
struct GenericSignatureParts {
548+
ArrayRef<CanGenericTypeParamType> params;
549+
unsigned initialParamDepth = 0;
550+
SmallVector<Requirement, 2> requirements;
551+
SmallVector<InverseRequirement, 2> inverses;
552+
bool isNull() const; // Is there anything to mangle?
553+
bool hasRequirements() const; // Are there any requirements to mangle?
554+
void clear();
555+
};
556+
557+
/// Append a generic signature to the mangling.
558+
///
559+
/// \param sig The generic signature.
560+
///
561+
/// \returns \c true if a generic signature was appended, \c false
562+
/// if it was empty.
563+
bool appendGenericSignature(GenericSignature sig);
564+
506565
/// Append a generic signature to the mangling.
507566
///
508567
/// \param sig The generic signature.
509568
///
510569
/// \param contextSig The signature of the known context. This function
511570
/// will only mangle the difference between \c sig and \c contextSig.
512571
///
572+
/// \param base The signature of the base entity whose generic signature we're
573+
/// mangling. This function will only mangle the inverses on generic
574+
/// parameter in \c sig that are not eliminated by conformance requirements in
575+
/// \c base.
576+
///
577+
///
513578
/// \returns \c true if a generic signature was appended, \c false
514579
/// if it was empty.
515580
bool appendGenericSignature(GenericSignature sig,
516-
GenericSignature contextSig = nullptr);
581+
GenericSignature contextSig,
582+
BaseEntitySignature &base);
517583

518584
/// Append a requirement to the mangling.
519585
///
@@ -527,10 +593,23 @@ class ASTMangler : public Mangler {
527593
void appendRequirement(const Requirement &reqt, GenericSignature sig,
528594
bool lhsBaseIsProtocolSelf = false);
529595

596+
/// Append an inverse requirement into the mangling.
597+
///
598+
/// Instead of mangling the presence of an invertible protocol, we mangle
599+
/// their absence, which is what an inverse represents.
600+
///
601+
/// \param req The inverse requirement to mangle.
602+
void appendInverseRequirement(const InverseRequirement &req,
603+
GenericSignature sig,
604+
bool lhsBaseIsProtocolSelf = false);
605+
606+
void gatherGenericSignatureParts(GenericSignature sig,
607+
GenericSignature contextSig,
608+
BaseEntitySignature &base,
609+
GenericSignatureParts &parts);
610+
530611
void appendGenericSignatureParts(GenericSignature sig,
531-
ArrayRef<CanTypeWrapper<GenericTypeParamType>> params,
532-
unsigned initialParamDepth,
533-
ArrayRef<Requirement> requirements);
612+
GenericSignatureParts const& parts);
534613

535614
DependentMemberType *dropProtocolFromAssociatedType(DependentMemberType *dmt,
536615
GenericSignature sig);
@@ -560,6 +639,7 @@ class ASTMangler : public Mangler {
560639

561640

562641
void appendDeclType(const ValueDecl *decl,
642+
BaseEntitySignature &base,
563643
FunctionManglingKind functionMangling = NoFunctionMangling);
564644

565645
bool tryAppendStandardSubstitution(const GenericTypeDecl *type);
@@ -575,7 +655,10 @@ class ASTMangler : public Mangler {
575655
void appendAccessorEntity(StringRef accessorKindCode,
576656
const AbstractStorageDecl *decl, bool isStatic);
577657

578-
void appendEntity(const ValueDecl *decl, StringRef EntityOp, bool isStatic);
658+
void appendEntity(const ValueDecl *decl,
659+
BaseEntitySignature &base,
660+
StringRef EntityOp,
661+
bool isStatic);
579662

580663
void appendEntity(const ValueDecl *decl);
581664

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
@@ -491,7 +491,10 @@ DECL_ATTR(_distributedThunkTarget, DistributedThunkTarget,
491491
DECL_ATTR(_allowFeatureSuppression, AllowFeatureSuppression,
492492
OnAnyDecl | UserInaccessible | NotSerialized | ABIStableToAdd | APIStableToAdd | ABIStableToRemove | APIStableToRemove,
493493
157)
494-
LAST_DECL_ATTR(AllowFeatureSuppression)
494+
SIMPLE_DECL_ATTR(_preInverseGenerics, PreInverseGenerics,
495+
OnAbstractFunction | OnSubscript | OnVar | UserInaccessible | ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove,
496+
158)
497+
LAST_DECL_ATTR(PreInverseGenerics)
495498

496499
#undef DECL_ATTR_ALIAS
497500
#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)