Skip to content

Commit bd82463

Browse files
committedAug 11, 2017
Add an AST-level abstraction for representing an abstract associated
type or conformance requirement. NFC.
1 parent baed726 commit bd82463

11 files changed

+262
-82
lines changed
 
+167
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
//===--- ProtocolAssociations.h - Associated types/conformances -*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 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 types for representing types and conformances
14+
// associated with a protocol.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef SWIFT_AST_PROTOCOLASSOCIATIONS_H
19+
#define SWIFT_AST_PROTOCOLASSOCIATIONS_H
20+
21+
#include "swift/AST/Decl.h"
22+
#include "llvm/ADT/DenseMapInfo.h"
23+
24+
namespace swift {
25+
26+
/// A type associated with a protocol.
27+
///
28+
/// This struct exists largely so that we can maybe eventually
29+
/// generalize it to an arbitrary path.
30+
class AssociatedType {
31+
AssociatedTypeDecl *Association;
32+
using AssociationInfo = llvm::DenseMapInfo<AssociatedTypeDecl*>;
33+
34+
struct SpecialValue {};
35+
explicit AssociatedType(SpecialValue _, AssociatedTypeDecl *specialValue)
36+
: Association(specialValue) {}
37+
38+
public:
39+
explicit AssociatedType(AssociatedTypeDecl *association)
40+
: Association(association) {
41+
assert(association);
42+
}
43+
44+
ProtocolDecl *getSourceProtocol() const {
45+
return Association->getProtocol();
46+
}
47+
48+
AssociatedTypeDecl *getAssociation() const {
49+
return Association;
50+
}
51+
52+
friend bool operator==(AssociatedType lhs, AssociatedType rhs) {
53+
return lhs.Association == rhs.Association;
54+
}
55+
friend bool operator!=(AssociatedType lhs, AssociatedType rhs) {
56+
return !(lhs == rhs);
57+
}
58+
59+
unsigned getHashValue() const {
60+
return llvm::hash_value(Association);
61+
}
62+
63+
static AssociatedType getEmptyKey() {
64+
return AssociatedType(SpecialValue(), AssociationInfo::getEmptyKey());
65+
}
66+
static AssociatedType getTombstoneKey() {
67+
return AssociatedType(SpecialValue(), AssociationInfo::getTombstoneKey());
68+
}
69+
};
70+
71+
/// A conformance associated with a protocol.
72+
class AssociatedConformance {
73+
ProtocolDecl *Source;
74+
CanType Association;
75+
ProtocolDecl *Requirement;
76+
77+
using SourceInfo = llvm::DenseMapInfo<ProtocolDecl*>;
78+
79+
explicit AssociatedConformance(ProtocolDecl *specialValue)
80+
: Source(specialValue), Association(CanType()), Requirement(nullptr) {}
81+
82+
public:
83+
explicit AssociatedConformance(ProtocolDecl *source, CanType association,
84+
ProtocolDecl *requirement)
85+
: Source(source), Association(association), Requirement(requirement) {
86+
assert(source && association && requirement);
87+
}
88+
89+
ProtocolDecl *getSourceProtocol() const {
90+
return Source;
91+
}
92+
93+
CanType getAssociation() const {
94+
return Association;
95+
}
96+
97+
ProtocolDecl *getAssociatedRequirement() const {
98+
return Requirement;
99+
}
100+
101+
friend bool operator==(const AssociatedConformance &lhs,
102+
const AssociatedConformance &rhs) {
103+
return lhs.Source == rhs.Source &&
104+
lhs.Association == rhs.Association &&
105+
lhs.Requirement == rhs.Requirement;
106+
}
107+
friend bool operator!=(const AssociatedConformance &lhs,
108+
const AssociatedConformance &rhs) {
109+
return !(lhs == rhs);
110+
}
111+
112+
unsigned getHashValue() const {
113+
return hash_value(llvm::hash_combine(Source,
114+
Association.getPointer(),
115+
Requirement));
116+
}
117+
118+
static AssociatedConformance getEmptyKey() {
119+
return AssociatedConformance(SourceInfo::getEmptyKey());
120+
}
121+
static AssociatedConformance getTombstoneKey() {
122+
return AssociatedConformance(SourceInfo::getTombstoneKey());
123+
}
124+
};
125+
126+
} // end namespace swift
127+
128+
namespace llvm {
129+
template <> struct DenseMapInfo<swift::AssociatedType> {
130+
static inline swift::AssociatedType getEmptyKey() {
131+
return swift::AssociatedType::getEmptyKey();
132+
}
133+
134+
static inline swift::AssociatedType getTombstoneKey() {
135+
return swift::AssociatedType::getTombstoneKey();
136+
}
137+
138+
static unsigned getHashValue(swift::AssociatedType val) {
139+
return val.getHashValue();
140+
}
141+
142+
static bool isEqual(swift::AssociatedType lhs, swift::AssociatedType rhs) {
143+
return lhs == rhs;
144+
}
145+
};
146+
147+
template <> struct DenseMapInfo<swift::AssociatedConformance> {
148+
static inline swift::AssociatedConformance getEmptyKey() {
149+
return swift::AssociatedConformance::getEmptyKey();
150+
}
151+
152+
static inline swift::AssociatedConformance getTombstoneKey() {
153+
return swift::AssociatedConformance::getTombstoneKey();
154+
}
155+
156+
static unsigned getHashValue(swift::AssociatedConformance val) {
157+
return val.getHashValue();
158+
}
159+
160+
static bool isEqual(swift::AssociatedConformance lhs,
161+
swift::AssociatedConformance rhs) {
162+
return lhs == rhs;
163+
}
164+
};
165+
}
166+
167+
#endif

‎include/swift/IRGen/Linking.h

+7-5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define SWIFT_IRGEN_LINKING_H
1515

1616
#include "swift/AST/Decl.h"
17+
#include "swift/AST/ProtocolAssociations.h"
1718
#include "swift/AST/ProtocolConformance.h"
1819
#include "swift/AST/Types.h"
1920
#include "swift/IRGen/ValueWitness.h"
@@ -509,21 +510,22 @@ class LinkEntity {
509510

510511
static LinkEntity
511512
forAssociatedTypeMetadataAccessFunction(const ProtocolConformance *C,
512-
AssociatedTypeDecl *associate) {
513+
AssociatedType association) {
513514
LinkEntity entity;
514515
entity.setForProtocolConformanceAndAssociatedType(
515-
Kind::AssociatedTypeMetadataAccessFunction, C, associate);
516+
Kind::AssociatedTypeMetadataAccessFunction, C,
517+
association.getAssociation());
516518
return entity;
517519
}
518520

519521
static LinkEntity
520522
forAssociatedTypeWitnessTableAccessFunction(const ProtocolConformance *C,
521-
CanType associatedType,
522-
ProtocolDecl *associatedProtocol){
523+
const AssociatedConformance &association) {
523524
LinkEntity entity;
524525
entity.setForProtocolConformanceAndAssociatedConformance(
525526
Kind::AssociatedTypeWitnessTableAccessFunction, C,
526-
associatedType, associatedProtocol);
527+
association.getAssociation(),
528+
association.getAssociatedRequirement());
527529
return entity;
528530
}
529531

‎include/swift/SIL/SILWitnessVisitor.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include "swift/AST/ASTVisitor.h"
2323
#include "swift/AST/Decl.h"
24+
#include "swift/AST/ProtocolAssociations.h"
2425
#include "swift/AST/Types.h"
2526
#include "swift/SIL/TypeLowering.h"
2627
#include "llvm/ADT/SmallVector.h"
@@ -59,7 +60,7 @@ template <class T> class SILWitnessVisitor : public ASTVisitor<T> {
5960
for (Decl *member : protocol->getMembers()) {
6061
if (auto associatedType = dyn_cast<AssociatedTypeDecl>(member)) {
6162
// TODO: only add associated types when they're new?
62-
asDerived().addAssociatedType(associatedType);
63+
asDerived().addAssociatedType(AssociatedType(associatedType));
6364
}
6465
}
6566
};
@@ -100,7 +101,8 @@ template <class T> class SILWitnessVisitor : public ASTVisitor<T> {
100101
addAssociatedTypes();
101102

102103
// Otherwise, add an associated requirement.
103-
asDerived().addAssociatedConformance(type, requirement);
104+
AssociatedConformance assocConf(protocol, type, requirement);
105+
asDerived().addAssociatedConformance(assocConf);
104106
continue;
105107
}
106108
}

‎lib/IRGen/GenArchetype.cpp

+8-7
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ llvm::Value *irgen::emitArchetypeTypeMetadataRef(IRGenFunction &IGF,
6464
"type metadata for primary archetype was not bound in context");
6565

6666
CanArchetypeType parent(archetype->getParent());
67-
metadata = emitAssociatedTypeMetadataRef(IGF, parent,
68-
archetype->getAssocType());
67+
AssociatedType association(archetype->getAssocType());
68+
metadata = emitAssociatedTypeMetadataRef(IGF, parent, association);
6969

7070
setTypeMetadataName(IGF.IGM, metadata, archetype);
7171

@@ -242,8 +242,8 @@ llvm::Value *irgen::emitArchetypeWitnessTableRef(IRGenFunction &IGF,
242242

243243
// Otherwise, it's an associated conformance requirement.
244244
} else {
245-
WitnessIndex index =
246-
lastPI.getAssociatedConformanceIndex(depType, requirement);
245+
AssociatedConformance association(lastProtocol, depType, requirement);
246+
WitnessIndex index = lastPI.getAssociatedConformanceIndex(association);
247247
path.addAssociatedConformanceComponent(index);
248248
}
249249

@@ -263,15 +263,16 @@ llvm::Value *irgen::emitArchetypeWitnessTableRef(IRGenFunction &IGF,
263263

264264
llvm::Value *irgen::emitAssociatedTypeMetadataRef(IRGenFunction &IGF,
265265
CanArchetypeType origin,
266-
AssociatedTypeDecl *associate) {
266+
AssociatedType association) {
267267
// Find the conformance of the origin to the associated type's protocol.
268268
llvm::Value *wtable = emitArchetypeWitnessTableRef(IGF, origin,
269-
associate->getProtocol());
269+
association.getSourceProtocol());
270270

271271
// Find the origin's type metadata.
272272
llvm::Value *originMetadata = emitArchetypeTypeMetadataRef(IGF, origin);
273273

274-
return emitAssociatedTypeMetadataRef(IGF, originMetadata, wtable, associate);
274+
return emitAssociatedTypeMetadataRef(IGF, originMetadata, wtable,
275+
association);
275276
}
276277

277278
const TypeInfo *TypeConverter::convertArchetypeType(ArchetypeType *archetype) {

‎lib/IRGen/GenArchetype.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ namespace llvm {
2525
}
2626

2727
namespace swift {
28+
class AssociatedType;
2829
class ProtocolDecl;
2930
class SILType;
3031

@@ -47,7 +48,7 @@ namespace irgen {
4748
/// Emit a metadata reference for an associated type of an archetype.
4849
llvm::Value *emitAssociatedTypeMetadataRef(IRGenFunction &IGF,
4950
CanArchetypeType origin,
50-
AssociatedTypeDecl *associate);
51+
AssociatedType association);
5152

5253
/// Emit a dynamic metatype lookup for the given archetype.
5354
llvm::Value *emitDynamicTypeOfOpaqueArchetype(IRGenFunction &IGF,

‎lib/IRGen/GenDecl.cpp

+5-6
Original file line numberDiff line numberDiff line change
@@ -3439,11 +3439,12 @@ IRGenModule::getAddrOfWitnessTable(const NormalProtocolConformance *conf,
34393439
llvm::Function *
34403440
IRGenModule::getAddrOfAssociatedTypeMetadataAccessFunction(
34413441
const NormalProtocolConformance *conformance,
3442-
AssociatedTypeDecl *associate) {
3442+
AssociatedType association) {
34433443
auto forDefinition = ForDefinition;
34443444

34453445
LinkEntity entity =
3446-
LinkEntity::forAssociatedTypeMetadataAccessFunction(conformance, associate);
3446+
LinkEntity::forAssociatedTypeMetadataAccessFunction(conformance,
3447+
association);
34473448
llvm::Function *&entry = GlobalFuncs[entity];
34483449
if (entry) {
34493450
if (forDefinition) updateLinkageForDefinition(*this, entry, entity);
@@ -3459,14 +3460,12 @@ IRGenModule::getAddrOfAssociatedTypeMetadataAccessFunction(
34593460
llvm::Function *
34603461
IRGenModule::getAddrOfAssociatedTypeWitnessTableAccessFunction(
34613462
const NormalProtocolConformance *conformance,
3462-
CanType associatedType,
3463-
ProtocolDecl *associatedProtocol) {
3463+
const AssociatedConformance &association) {
34643464
auto forDefinition = ForDefinition;
34653465

34663466
LinkEntity entity =
34673467
LinkEntity::forAssociatedTypeWitnessTableAccessFunction(conformance,
3468-
associatedType,
3469-
associatedProtocol);
3468+
association);
34703469
llvm::Function *&entry = GlobalFuncs[entity];
34713470
if (entry) {
34723471
if (forDefinition) updateLinkageForDefinition(*this, entry, entity);

0 commit comments

Comments
 (0)