Skip to content

Commit d3de4f2

Browse files
authored
Merge pull request swiftlang#12321 from DougGregor/assoc-type-overrides
Track "overrides" of associated types
2 parents 70dd884 + f51d5b6 commit d3de4f2

19 files changed

+366
-98
lines changed

include/swift/AST/Decl.h

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -562,8 +562,10 @@ class alignas(1 << DeclAlignInBits) Decl {
562562
class AssociatedTypeDeclBitfields {
563563
friend class AssociatedTypeDecl;
564564
unsigned : NumTypeDeclBits;
565+
unsigned ComputedOverridden : 1;
566+
unsigned HasOverridden : 1;
565567
};
566-
enum { NumAssociatedTypeDeclBits = NumTypeDeclBits };
568+
enum { NumAssociatedTypeDeclBits = NumTypeDeclBits + 2 };
567569
static_assert(NumAssociatedTypeDeclBits <= 32, "fits in an unsigned");
568570

569571
class ImportDeclBitfields {
@@ -2665,6 +2667,33 @@ class AssociatedTypeDecl : public AbstractTypeParamDecl {
26652667
/// type; can only be called after the alias type has been resolved.
26662668
void computeType();
26672669

2670+
/// Retrieve the associated type "anchor", which is the associated type
2671+
/// declaration that will be used to describe this associated type in the
2672+
/// ABI.
2673+
///
2674+
/// The associated type "anchor" is an associated type that does not
2675+
/// override any other associated type. There may be several such associated
2676+
/// types; select one deterministically.
2677+
AssociatedTypeDecl *getAssociatedTypeAnchor() const;
2678+
2679+
/// Retrieve the (first) overridden associated type declaration, if any.
2680+
AssociatedTypeDecl *getOverriddenDecl() const;
2681+
2682+
/// Retrieve the set of associated types overridden by this associated
2683+
/// type.
2684+
ArrayRef<AssociatedTypeDecl *> getOverriddenDecls() const;
2685+
2686+
/// Whether the overridden declarations have already been computed.
2687+
bool overriddenDeclsComputed() const {
2688+
return AssociatedTypeDeclBits.ComputedOverridden;
2689+
}
2690+
2691+
/// Record the set of overridden declarations.
2692+
///
2693+
/// \returns the array recorded in the AST.
2694+
ArrayRef<AssociatedTypeDecl *> setOverriddenDecls(
2695+
ArrayRef<AssociatedTypeDecl *> overridden);
2696+
26682697
SourceLoc getStartLoc() const { return KeywordLoc; }
26692698
SourceRange getSourceRange() const;
26702699

include/swift/AST/GenericSignatureBuilder.h

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1452,18 +1452,13 @@ class GenericSignatureBuilder::PotentialArchetype {
14521452
/// associated type.
14531453
PotentialArchetype(PotentialArchetype *parent, Identifier name);
14541454

1455-
/// \brief Construct a new potential archetype for an associated type.
1456-
PotentialArchetype(PotentialArchetype *parent, AssociatedTypeDecl *assocType)
1457-
: parentOrBuilder(parent), identifier(assocType)
1458-
{
1459-
assert(parent != nullptr && "Not an associated type?");
1460-
}
1461-
14621455
/// \brief Construct a new potential archetype for a concrete declaration.
14631456
PotentialArchetype(PotentialArchetype *parent, TypeDecl *concreteDecl)
14641457
: parentOrBuilder(parent), identifier(concreteDecl)
14651458
{
1466-
assert(parent != nullptr && "Not an associated type?");
1459+
assert(parent != nullptr && "Not a nested type?");
1460+
assert(!isa<AssociatedTypeDecl>(concreteDecl) ||
1461+
cast<AssociatedTypeDecl>(concreteDecl)->getOverriddenDecls().empty());
14671462
}
14681463

14691464
/// \brief Construct a new potential archetype for a generic parameter.

include/swift/Serialization/ModuleFormat.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const uint16_t VERSION_MAJOR = 0;
5454
/// in source control, you should also update the comment to briefly
5555
/// describe what change you made. The content of this comment isn't important;
5656
/// it just ensures a conflict if two people change the module format.
57-
const uint16_t VERSION_MINOR = 368; // Last change: objc_method, objc_super_method
57+
const uint16_t VERSION_MINOR = 369; // Last change: associated type overrides
5858

5959
using DeclID = PointerEmbeddedInt<unsigned, 31>;
6060
using DeclIDField = BCFixed<31>;
@@ -815,10 +815,11 @@ namespace decls_block {
815815

816816
using AssociatedTypeDeclLayout = BCRecordLayout<
817817
ASSOCIATED_TYPE_DECL,
818-
IdentifierIDField, // name
819-
DeclContextIDField,// context decl
820-
TypeIDField, // default definition
821-
BCFixed<1> // implicit flag
818+
IdentifierIDField, // name
819+
DeclContextIDField, // context decl
820+
TypeIDField, // default definition
821+
BCFixed<1>, // implicit flag
822+
BCArray<DeclIDField> // overridden associated types
822823
>;
823824

824825
using StructLayout = BCRecordLayout<

lib/AST/ASTContext.cpp

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,10 @@ FOR_KNOWN_FOUNDATION_TYPES(CACHE_FOUNDATION_DECL)
278278
/// The existential signature <T : P> for each P.
279279
llvm::DenseMap<CanType, CanGenericSignature> ExistentialSignatures;
280280

281+
/// Overridden associated type declarations.
282+
llvm::DenseMap<const AssociatedTypeDecl *, ArrayRef<AssociatedTypeDecl *>>
283+
AssociatedTypeOverrides;
284+
281285
/// \brief Structure that captures data that is segregated into different
282286
/// arenas.
283287
struct Arena {
@@ -1541,6 +1545,125 @@ GenericEnvironment *ASTContext::getOrCreateCanonicalGenericEnvironment(
15411545
return env;
15421546
}
15431547

1548+
/// Minimize the set of overridden associated types, eliminating any
1549+
/// associated types that are overridden by other associated types.
1550+
static void minimizeOverriddenAssociatedTypes(
1551+
SmallVectorImpl<AssociatedTypeDecl *> &assocTypes) {
1552+
// Mark associated types that are "worse" than some other associated type,
1553+
// because they come from an inherited protocol.
1554+
bool anyWorse = false;
1555+
std::vector<bool> worseThanAny(assocTypes.size(), false);
1556+
for (unsigned i : indices(assocTypes)) {
1557+
auto proto1 = assocTypes[i]->getProtocol();
1558+
for (unsigned j : range(i + 1, assocTypes.size())) {
1559+
auto proto2 = assocTypes[j]->getProtocol();
1560+
if (proto1->inheritsFrom(proto2)) {
1561+
anyWorse = true;
1562+
worseThanAny[j] = true;
1563+
} else if (proto2->inheritsFrom(proto1)) {
1564+
anyWorse = true;
1565+
worseThanAny[i] = true;
1566+
break;
1567+
}
1568+
}
1569+
}
1570+
1571+
// If we didn't find any associated types that were "worse", we're done.
1572+
if (!anyWorse) return;
1573+
1574+
// Copy in the associated types that aren't worse than any other associated
1575+
// type.
1576+
unsigned nextIndex = 0;
1577+
for (unsigned i : indices(assocTypes)) {
1578+
if (worseThanAny[i]) continue;
1579+
assocTypes[nextIndex++] = assocTypes[i];
1580+
}
1581+
1582+
assocTypes.erase(assocTypes.begin() + nextIndex, assocTypes.end());
1583+
}
1584+
1585+
/// Sort associated types just based on the protocol.
1586+
static int compareSimilarAssociatedTypes(AssociatedTypeDecl *const *lhs,
1587+
AssociatedTypeDecl *const *rhs) {
1588+
auto lhsProto = (*lhs)->getProtocol();
1589+
auto rhsProto = (*rhs)->getProtocol();
1590+
return ProtocolType::compareProtocols(&lhsProto, &rhsProto);
1591+
}
1592+
1593+
ArrayRef<AssociatedTypeDecl *> AssociatedTypeDecl::getOverriddenDecls() const {
1594+
// If we already computed the set of overridden associated types, return it.
1595+
if (AssociatedTypeDeclBits.ComputedOverridden) {
1596+
// We didn't override any associated types, so return the empty set.
1597+
if (!AssociatedTypeDeclBits.HasOverridden)
1598+
return { };
1599+
1600+
// Look up the overrides.
1601+
auto known = getASTContext().Impl.AssociatedTypeOverrides.find(this);
1602+
assert(known != getASTContext().Impl.AssociatedTypeOverrides.end());
1603+
return known->second;
1604+
}
1605+
1606+
// Find associated types with the given name in all of the inherited
1607+
// protocols.
1608+
SmallVector<AssociatedTypeDecl *, 4> inheritedAssociatedTypes;
1609+
auto proto = getProtocol();
1610+
proto->walkInheritedProtocols([&](ProtocolDecl *inheritedProto) {
1611+
if (proto == inheritedProto) return TypeWalker::Action::Continue;
1612+
1613+
// Objective-C protocols
1614+
if (inheritedProto->isObjC()) return TypeWalker::Action::Continue;
1615+
1616+
// Look for associated types with the same name.
1617+
bool foundAny = false;
1618+
for (auto member : inheritedProto->lookupDirect(
1619+
getFullName(),
1620+
/*ignoreNewExtensions=*/true)) {
1621+
if (auto assocType = dyn_cast<AssociatedTypeDecl>(member)) {
1622+
inheritedAssociatedTypes.push_back(assocType);
1623+
foundAny = true;
1624+
}
1625+
}
1626+
1627+
return foundAny ? TypeWalker::Action::SkipChildren
1628+
: TypeWalker::Action::Continue;
1629+
});
1630+
1631+
// Minimize the set of inherited associated types, eliminating any that
1632+
// themselves are overridden.
1633+
minimizeOverriddenAssociatedTypes(inheritedAssociatedTypes);
1634+
1635+
// Sort the set of inherited associated types.
1636+
llvm::array_pod_sort(inheritedAssociatedTypes.begin(),
1637+
inheritedAssociatedTypes.end(),
1638+
compareSimilarAssociatedTypes);
1639+
1640+
return const_cast<AssociatedTypeDecl *>(this)
1641+
->setOverriddenDecls(inheritedAssociatedTypes);
1642+
}
1643+
1644+
ArrayRef<AssociatedTypeDecl *> AssociatedTypeDecl::setOverriddenDecls(
1645+
ArrayRef<AssociatedTypeDecl *> overridden) {
1646+
assert(!AssociatedTypeDeclBits.ComputedOverridden &&
1647+
"Overridden decls already computed");
1648+
AssociatedTypeDeclBits.ComputedOverridden = true;
1649+
1650+
// If the set of overridden declarations is empty, note that.
1651+
if (overridden.empty()) {
1652+
AssociatedTypeDeclBits.HasOverridden = false;
1653+
return { };
1654+
}
1655+
1656+
// Record the overrides in the context.
1657+
auto &ctx = getASTContext();
1658+
AssociatedTypeDeclBits.HasOverridden = true;
1659+
auto overriddenCopy = ctx.AllocateCopy(overridden);
1660+
auto inserted =
1661+
ctx.Impl.AssociatedTypeOverrides.insert({this, overriddenCopy}).second;
1662+
(void)inserted;
1663+
assert(inserted && "Already recorded associated type overrides");
1664+
return overriddenCopy;
1665+
}
1666+
15441667
bool ASTContext::canImportModule(std::pair<Identifier, SourceLoc> ModulePath) {
15451668
// If this module has already been successfully imported, it is importable.
15461669
if (getLoadedModule(ModulePath) != nullptr)

lib/AST/ASTDumper.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,15 @@ namespace {
667667
[&](const RequirementRepr &req) { req.print(OS); },
668668
[&] { OS << ", "; });
669669
}
670+
if (decl->overriddenDeclsComputed()) {
671+
OS << " overridden=";
672+
interleave(decl->getOverriddenDecls(),
673+
[&](AssociatedTypeDecl *overridden) {
674+
OS << overridden->getProtocol()->getName();
675+
}, [&]() {
676+
OS << ", ";
677+
});
678+
}
670679

671680
OS << ")";
672681
}

lib/AST/Decl.cpp

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1621,6 +1621,8 @@ ValueDecl *ValueDecl::getOverriddenDecl() const {
16211621
return sdd->getOverriddenDecl();
16221622
if (auto cd = dyn_cast<ConstructorDecl>(this))
16231623
return cd->getOverriddenDecl();
1624+
if (auto at = dyn_cast<AssociatedTypeDecl>(this))
1625+
return at->getOverriddenDecl();
16241626
return nullptr;
16251627
}
16261628

@@ -2608,7 +2610,11 @@ AssociatedTypeDecl::AssociatedTypeDecl(DeclContext *dc, SourceLoc keywordLoc,
26082610
TrailingWhereClause *trailingWhere)
26092611
: AbstractTypeParamDecl(DeclKind::AssociatedType, dc, name, nameLoc),
26102612
KeywordLoc(keywordLoc), DefaultDefinition(defaultDefinition),
2611-
TrailingWhere(trailingWhere) {}
2613+
TrailingWhere(trailingWhere) {
2614+
2615+
AssociatedTypeDeclBits.ComputedOverridden = false;
2616+
AssociatedTypeDeclBits.HasOverridden = false;
2617+
}
26122618

26132619
AssociatedTypeDecl::AssociatedTypeDecl(DeclContext *dc, SourceLoc keywordLoc,
26142620
Identifier name, SourceLoc nameLoc,
@@ -2619,6 +2625,8 @@ AssociatedTypeDecl::AssociatedTypeDecl(DeclContext *dc, SourceLoc keywordLoc,
26192625
KeywordLoc(keywordLoc), TrailingWhere(trailingWhere),
26202626
Resolver(definitionResolver), ResolverContextData(resolverData) {
26212627
assert(Resolver && "missing resolver");
2628+
AssociatedTypeDeclBits.ComputedOverridden = false;
2629+
AssociatedTypeDeclBits.HasOverridden = false;
26222630
}
26232631

26242632
void AssociatedTypeDecl::computeType() {
@@ -2645,6 +2653,29 @@ SourceRange AssociatedTypeDecl::getSourceRange() const {
26452653
return SourceRange(KeywordLoc, endLoc);
26462654
}
26472655

2656+
AssociatedTypeDecl *AssociatedTypeDecl::getAssociatedTypeAnchor() const {
2657+
auto overridden = getOverriddenDecls();
2658+
2659+
// If this declaration does not override any other declarations, it's
2660+
// the anchor.
2661+
if (overridden.empty()) return const_cast<AssociatedTypeDecl *>(this);
2662+
2663+
// Find the best anchor among the anchors of the overridden decls.
2664+
AssociatedTypeDecl *bestAnchor = nullptr;
2665+
for (auto assocType : overridden) {
2666+
auto anchor = assocType->getAssociatedTypeAnchor();
2667+
if (!bestAnchor || compare(anchor, bestAnchor) < 0)
2668+
bestAnchor = anchor;
2669+
}
2670+
2671+
return bestAnchor;
2672+
}
2673+
2674+
AssociatedTypeDecl *AssociatedTypeDecl::getOverriddenDecl() const {
2675+
auto overridden = getOverriddenDecls();
2676+
return overridden.empty() ? nullptr : overridden.front();
2677+
}
2678+
26482679
EnumDecl::EnumDecl(SourceLoc EnumLoc,
26492680
Identifier Name, SourceLoc NameLoc,
26502681
MutableArrayRef<TypeLoc> Inherited,

0 commit comments

Comments
 (0)