Skip to content

Commit 83db811

Browse files
authored
Merge pull request #80225 from DougGregor/conforming-type-in-abstract-conformance
Store the conforming type within an abstract ProtocolConformanceRef
2 parents a59a2a1 + 731f584 commit 83db811

Some content is hidden

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

49 files changed

+389
-132
lines changed

include/swift/AST/ASTBridgingImpl.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@ BridgedASTType BridgedConformance::getType() const {
602602
}
603603

604604
BridgedDeclObj BridgedConformance::getRequirement() const {
605-
return {unbridged().getRequirement()};
605+
return {unbridged().getProtocol()};
606606
}
607607

608608
BridgedConformance BridgedConformance::getGenericConformance() const {

include/swift/AST/ProtocolConformanceRef.h

+55-14
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,24 @@
2626
#include "llvm/ADT/STLExtras.h"
2727
#include <optional>
2828

29+
namespace swift {
30+
class AbstractConformance;
31+
}
32+
2933
namespace llvm {
30-
class raw_ostream;
34+
class raw_ostream;
35+
36+
template <>
37+
struct PointerLikeTypeTraits<swift::AbstractConformance *> {
38+
public:
39+
static inline void *getAsVoidPointer(swift::AbstractConformance *ptr) {
40+
return ptr;
41+
}
42+
static inline swift::AbstractConformance *getFromVoidPointer(void *ptr) {
43+
return (swift::AbstractConformance *)ptr;
44+
}
45+
enum { NumLowBitsAvailable = swift::TypeAlignInBits };
46+
};
3147
}
3248

3349
namespace swift {
@@ -53,22 +69,27 @@ enum class EffectKind : uint8_t;
5369
/// ProtocolConformanceRef allows the efficient recovery of the protocol
5470
/// even when the conformance is abstract.
5571
class ProtocolConformanceRef {
56-
using UnionType = llvm::PointerUnion<ProtocolDecl *,
72+
public:
73+
using UnionType = llvm::PointerUnion<AbstractConformance *,
5774
ProtocolConformance *,
5875
PackConformance *>;
76+
77+
private:
5978
UnionType Union;
6079

6180
explicit ProtocolConformanceRef(UnionType value) : Union(value) {}
6281

82+
public:
83+
ProtocolConformanceRef() : Union() {}
84+
ProtocolConformanceRef(std::nullptr_t) : Union() {}
85+
6386
/// Create an abstract protocol conformance reference.
64-
explicit ProtocolConformanceRef(ProtocolDecl *proto) : Union(proto) {
65-
assert(proto != nullptr &&
87+
explicit ProtocolConformanceRef(AbstractConformance *abstract)
88+
: Union(abstract) {
89+
assert(abstract != nullptr &&
6690
"cannot construct ProtocolConformanceRef with null");
6791
}
6892

69-
public:
70-
ProtocolConformanceRef() : Union() {}
71-
7293
/// Create a concrete protocol conformance reference.
7394
explicit ProtocolConformanceRef(ProtocolConformance *conf) : Union(conf) {
7495
assert(conf != nullptr &&
@@ -95,7 +116,7 @@ class ProtocolConformanceRef {
95116
explicit operator bool() const { return !isInvalid(); }
96117

97118
/// Create an abstract conformance for a type parameter or archetype.
98-
static ProtocolConformanceRef forAbstract(Type subjectType,
119+
static ProtocolConformanceRef forAbstract(Type conformingType,
99120
ProtocolDecl *protocol);
100121

101122
bool isConcrete() const {
@@ -115,12 +136,11 @@ class ProtocolConformanceRef {
115136
}
116137

117138
bool isAbstract() const {
118-
return !isInvalid() && Union.is<ProtocolDecl*>();
139+
return !isInvalid() && Union.is<AbstractConformance*>();
119140
}
120141

121-
ProtocolDecl *getAbstract() const {
122-
ASSERT(isAbstract());
123-
return Union.get<ProtocolDecl*>();
142+
AbstractConformance *getAbstract() const {
143+
return Union.get<AbstractConformance *>();
124144
}
125145

126146
/// Determine whether this conformance (or a conformance it depends on)
@@ -149,7 +169,7 @@ class ProtocolConformanceRef {
149169
/// The given `body` will be called on each isolated conformance. If it ever
150170
/// returns `true`, this function will abort the search and return `true`.
151171
bool forEachIsolatedConformance(
152-
llvm::function_ref<bool(ProtocolConformance*)> body
172+
llvm::function_ref<bool(ProtocolConformanceRef)> body
153173
) const;
154174

155175
using OpaqueValue = void*;
@@ -158,8 +178,11 @@ class ProtocolConformanceRef {
158178
return ProtocolConformanceRef(UnionType::getFromOpaqueValue(value));
159179
}
160180

181+
/// Retrieve the conforming type.
182+
Type getType() const;
183+
161184
/// Return the protocol requirement.
162-
ProtocolDecl *getRequirement() const;
185+
ProtocolDecl *getProtocol() const;
163186

164187
/// Apply a substitution to the conforming type.
165188
ProtocolConformanceRef subst(Type origType, SubstitutionMap subMap,
@@ -240,4 +263,22 @@ SourceLoc extractNearestSourceLoc(const ProtocolConformanceRef conformanceRef);
240263

241264
} // end namespace swift
242265

266+
namespace llvm {
267+
class raw_ostream;
268+
269+
template <>
270+
struct PointerLikeTypeTraits<swift::ProtocolConformanceRef>
271+
: PointerLikeTypeTraits<swift::ProtocolConformanceRef::UnionType>
272+
{
273+
public:
274+
static inline void *getAsVoidPointer(swift::ProtocolConformanceRef ref) {
275+
return ref.getOpaqueValue();
276+
}
277+
static inline swift::ProtocolConformanceRef getFromVoidPointer(void *ptr) {
278+
return swift::ProtocolConformanceRef::getFromOpaqueValue(ptr);
279+
}
280+
};
281+
282+
}
283+
243284
#endif // LLVM_SWIFT_AST_PROTOCOLCONFORMANCEREF_H

include/swift/AST/Requirement.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ class Requirement {
192192
CheckRequirementResult checkRequirement(
193193
SmallVectorImpl<Requirement> &subReqs,
194194
bool allowMissing = false,
195-
SmallVectorImpl<ProtocolConformance *> *isolatedConformances = nullptr
195+
SmallVectorImpl<ProtocolConformanceRef> *isolatedConformances = nullptr
196196
) const;
197197

198198
/// Determines if this substituted requirement can ever be satisfied,

lib/APIDigester/ModuleAnalyzerNodes.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1498,7 +1498,7 @@ SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, ImportDecl *ID):
14981498
}
14991499

15001500
SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, ProtocolConformanceRef Conform):
1501-
SDKNodeInitInfo(Ctx, Conform.getRequirement()) {
1501+
SDKNodeInitInfo(Ctx, Conform.getProtocol()) {
15021502
// The conformance can be conditional. The generic signature keeps track of
15031503
// the requirements.
15041504
if (Conform.isConcrete()) {

lib/AST/ASTContext.cpp

+35-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
//===----------------------------------------------------------------------===//
1616

1717
#include "swift/AST/ASTContext.h"
18+
#include "AbstractConformance.h"
1819
#include "ClangTypeConverter.h"
1920
#include "ForeignRepresentationInfo.h"
2021
#include "SubstitutionMapStorage.h"
@@ -596,6 +597,9 @@ struct ASTContext::Implementation {
596597
/// The set of substitution maps (uniqued by their storage).
597598
llvm::FoldingSet<SubstitutionMap::Storage> SubstitutionMaps;
598599

600+
/// The set of abstract conformances (uniqued by their storage).
601+
llvm::FoldingSet<AbstractConformance> AbstractConformances;
602+
599603
~Arena() {
600604
for (auto &conformance : SpecializedConformances)
601605
conformance.~SpecializedProtocolConformance();
@@ -3379,6 +3383,7 @@ void ASTContext::Implementation::Arena::dump(llvm::raw_ostream &os) const {
33793383
SIZE_AND_BYTES(BuiltinConformances);
33803384
SIZE(PackConformances);
33813385
SIZE(SubstitutionMaps);
3386+
SIZE(AbstractConformances);
33823387

33833388
#undef SIZE
33843389
#undef SIZE_AND_BYTES
@@ -5104,7 +5109,7 @@ void SILFunctionType::Profile(
51045109
invocationSubs.profile(id);
51055110
id.AddBoolean((bool)conformance);
51065111
if (conformance)
5107-
id.AddPointer(conformance.getRequirement());
5112+
id.AddPointer(conformance.getProtocol());
51085113
}
51095114

51105115
SILFunctionType::SILFunctionType(
@@ -5739,6 +5744,35 @@ SubstitutionMap::Storage *SubstitutionMap::Storage::get(
57395744
return result;
57405745
}
57415746

5747+
ProtocolConformanceRef ProtocolConformanceRef::forAbstract(
5748+
Type conformingType, ProtocolDecl *proto) {
5749+
ASTContext &ctx = proto->getASTContext();
5750+
5751+
// Figure out which arena this should go in.
5752+
RecursiveTypeProperties properties;
5753+
if (conformingType)
5754+
properties |= conformingType->getRecursiveProperties();
5755+
auto arena = getArena(properties);
5756+
5757+
// Profile the substitution map.
5758+
llvm::FoldingSetNodeID id;
5759+
AbstractConformance::Profile(id, conformingType, proto);
5760+
5761+
// Did we already record this abstract conformance?
5762+
void *insertPos;
5763+
auto &abstractConformances =
5764+
ctx.getImpl().getArena(arena).AbstractConformances;
5765+
if (auto result = abstractConformances.FindNodeOrInsertPos(id, insertPos))
5766+
return ProtocolConformanceRef(result);
5767+
5768+
// Allocate and record this abstract conformance.
5769+
auto mem = ctx.Allocate(sizeof(AbstractConformance),
5770+
alignof(AbstractConformance), arena);
5771+
auto result = new (mem) AbstractConformance(conformingType, proto);
5772+
abstractConformances.InsertNode(result, insertPos);
5773+
return ProtocolConformanceRef(result);
5774+
}
5775+
57425776
const AvailabilityContext::Storage *AvailabilityContext::Storage::get(
57435777
const AvailabilityRange &platformRange, bool isDeprecated,
57445778
llvm::ArrayRef<DomainInfo> domainInfos, const ASTContext &ctx) {

lib/AST/ASTDumper.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -5519,7 +5519,7 @@ class PrintConformance : public PrintBase {
55195519
assert(conformance.isAbstract());
55205520

55215521
printHead("abstract_conformance", ASTNodeColor, label);
5522-
printReferencedDeclField(conformance.getAbstract(),
5522+
printReferencedDeclField(conformance.getProtocol(),
55235523
Label::always("protocol"));
55245524
printFoot();
55255525
}

lib/AST/ASTMangler.cpp

+7-5
Original file line numberDiff line numberDiff line change
@@ -2170,7 +2170,7 @@ void ASTMangler::appendRetroactiveConformances(SubstitutionMap subMap,
21702170
if (conformance.isInvalid())
21712171
continue;
21722172

2173-
if (conformance.getRequirement()->isMarkerProtocol())
2173+
if (conformance.getProtocol()->isMarkerProtocol())
21742174
continue;
21752175

21762176
SWIFT_DEFER {
@@ -4528,7 +4528,7 @@ void ASTMangler::appendAnyProtocolConformance(
45284528
// If we have a conformance to a marker protocol but we aren't allowed to
45294529
// emit marker protocols, skip it.
45304530
if (!AllowMarkerProtocols &&
4531-
conformance.getRequirement()->isMarkerProtocol())
4531+
conformance.getProtocol()->isMarkerProtocol())
45324532
return;
45334533

45344534
// While all invertible protocols are marker protocols, do not mangle them
@@ -4537,15 +4537,17 @@ void ASTMangler::appendAnyProtocolConformance(
45374537
// but we *might* have let that slip by for the other cases below, so the
45384538
// early-exits are highly conservative.
45394539
const bool forInvertible =
4540-
conformance.getRequirement()->getInvertibleProtocolKind().has_value();
4540+
conformance.getProtocol()->getInvertibleProtocolKind().has_value();
45414541

45424542
if (conformingType->isTypeParameter()) {
45434543
assert(genericSig && "Need a generic signature to resolve conformance");
45444544
if (forInvertible)
45454545
return;
45464546

4547+
// FIXME: conformingType parameter should no longer be needed, because
4548+
// its in conformance.
45474549
auto path = genericSig->getConformancePath(conformingType,
4548-
conformance.getAbstract());
4550+
conformance.getProtocol());
45494551
appendDependentProtocolConformance(path, genericSig);
45504552
} else if (auto opaqueType = conformingType->getAs<OpaqueTypeArchetypeType>()) {
45514553
if (forInvertible)
@@ -4556,7 +4558,7 @@ void ASTMangler::appendAnyProtocolConformance(
45564558
ConformancePath conformancePath =
45574559
opaqueSignature->getConformancePath(
45584560
opaqueType->getInterfaceType(),
4559-
conformance.getAbstract());
4561+
conformance.getProtocol());
45604562

45614563
// Append the conformance path with the signature of the opaque type.
45624564
appendDependentProtocolConformance(conformancePath, opaqueSignature);

lib/AST/ASTPrinter.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -6634,7 +6634,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
66346634
case SILFunctionType::Representation::WitnessMethod:
66356635
Printer << "witness_method: ";
66366636
printTypeDeclName(
6637-
witnessMethodConformance.getRequirement()->getDeclaredType()
6637+
witnessMethodConformance.getProtocol()->getDeclaredType()
66386638
->castTo<ProtocolType>());
66396639
break;
66406640
case SILFunctionType::Representation::Closure:

lib/AST/ASTVerifier.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -1785,7 +1785,7 @@ class Verifier : public ASTWalker {
17851785
for (auto proto : erasedLayout.getProtocols()) {
17861786
if (std::find_if(conformances.begin(), conformances.end(),
17871787
[&](ProtocolConformanceRef ref) -> bool {
1788-
return ref.getRequirement() == proto->getDecl();
1788+
return ref.getProtocol() == proto->getDecl();
17891789
})
17901790
== conformances.end()) {
17911791
Out << "ErasureExpr is missing conformance for required protocol\n";
@@ -1819,7 +1819,7 @@ class Verifier : public ASTWalker {
18191819
anyHashableDecl->getDeclaredInterfaceType(),
18201820
"AnyHashableErasureExpr and the standard AnyHashable type");
18211821

1822-
if (E->getConformance().getRequirement() != hashableDecl) {
1822+
if (E->getConformance().getProtocol() != hashableDecl) {
18231823
Out << "conformance on AnyHashableErasureExpr was not for Hashable\n";
18241824
E->getConformance().dump(Out);
18251825
abort();
@@ -2811,7 +2811,7 @@ class Verifier : public ASTWalker {
28112811
if (!type->is<ArchetypeType>() && !type->isAnyExistentialType()) {
28122812
Out << "type " << type
28132813
<< " should not have an abstract conformance to "
2814-
<< conformance.getRequirement()->getName();
2814+
<< conformance.getProtocol()->getName();
28152815
abort();
28162816
}
28172817

lib/AST/AbstractConformance.h

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//===--- AbstractConformance.h - Abstract conformance storage ---*- 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 the AbstractConformance class, which stores an
14+
// abstract conformance that is stashed in a ProtocolConformanceRef.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
#ifndef SWIFT_AST_ABSTRACT_CONFORMANCE_H
18+
#define SWIFT_AST_ABSTRACT_CONFORMANCE_H
19+
20+
#include "swift/AST/Type.h"
21+
#include "llvm/ADT/FoldingSet.h"
22+
23+
namespace swift {
24+
class AbstractConformance final : public llvm::FoldingSetNode {
25+
Type conformingType;
26+
ProtocolDecl *requirement;
27+
28+
public:
29+
AbstractConformance(Type conformingType, ProtocolDecl *requirement)
30+
: conformingType(conformingType), requirement(requirement) { }
31+
32+
Type getType() const { return conformingType; }
33+
ProtocolDecl *getProtocol() const { return requirement; }
34+
35+
void Profile(llvm::FoldingSetNodeID &id) const {
36+
Profile(id, getType(), getProtocol());
37+
}
38+
39+
/// Profile the substitution map storage, for use with LLVM's FoldingSet.
40+
static void Profile(llvm::FoldingSetNodeID &id,
41+
Type conformingType,
42+
ProtocolDecl *requirement) {
43+
id.AddPointer(conformingType.getPointer());
44+
id.AddPointer(requirement);
45+
}
46+
};
47+
48+
}
49+
50+
#endif // SWIFT_AST_ABSTRACT_CONFORMANCE_H
51+

lib/AST/Effects.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ void swift::simple_display(llvm::raw_ostream &out,
136136

137137
bool ProtocolConformanceRef::hasEffect(EffectKind kind) const {
138138
if (!isConcrete()) { return kind != EffectKind::Unsafe; }
139-
return evaluateOrDefault(getRequirement()->getASTContext().evaluator,
139+
return evaluateOrDefault(getProtocol()->getASTContext().evaluator,
140140
ConformanceHasEffectRequest{kind, getConcrete()},
141141
true);
142142
}

0 commit comments

Comments
 (0)