Skip to content

Commit 8584e97

Browse files
committed
[AST] Sink ProtocolConformance::getWitness() down into NormalProtocolConformance.
NormalProtocolConformance has the only correct implementation of this functionality. Instead, providing a safer getWitnessDecl() that doesn't promise substitutions that are incorrect (and not actually used by any clients).
1 parent 8e2709a commit 8584e97

File tree

9 files changed

+68
-69
lines changed

9 files changed

+68
-69
lines changed

include/swift/AST/ProtocolConformance.h

Lines changed: 31 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -182,41 +182,16 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance {
182182
return false;
183183
}
184184

185-
/// Retrieve the non-type witness for the given requirement.
186-
Witness getWitness(ValueDecl *requirement, LazyResolver *resolver) const;
185+
/// Retrieve the value witness declaration corresponding to the given
186+
/// requirement.
187+
ValueDecl *getWitnessDecl(ValueDecl *requirement,
188+
LazyResolver *resolver) const;
187189

188190
private:
189191
/// Determine whether we have a witness for the given requirement.
190192
bool hasWitness(ValueDecl *requirement) const;
191193

192194
public:
193-
/// Apply the given function object to each value witness within this
194-
/// protocol conformance.
195-
///
196-
/// The function object should accept a \c ValueDecl* for the requirement
197-
/// followed by the \c Witness for the witness. Note that a generic
198-
/// witness will only be specialized if the conformance came from the current
199-
/// file.
200-
template<typename F>
201-
void forEachValueWitness(LazyResolver *resolver, F f) const {
202-
const ProtocolDecl *protocol = getProtocol();
203-
for (auto req : protocol->getMembers()) {
204-
auto valueReq = dyn_cast<ValueDecl>(req);
205-
if (!valueReq || isa<AssociatedTypeDecl>(valueReq) ||
206-
valueReq->isInvalid())
207-
continue;
208-
209-
if (!valueReq->isProtocolRequirement())
210-
continue;
211-
212-
// If we don't have and cannot resolve witnesses, skip it.
213-
if (!resolver && !hasWitness(valueReq))
214-
continue;
215-
216-
f(valueReq, getWitness(valueReq, resolver));
217-
}
218-
}
219-
220195
/// Retrieve the protocol conformance for the inherited protocol.
221196
ProtocolConformance *getInheritedConformance(ProtocolDecl *protocol) const;
222197

@@ -457,6 +432,33 @@ class NormalProtocolConformance : public ProtocolConformance,
457432
/// Set the witness for the given requirement.
458433
void setWitness(ValueDecl *requirement, Witness witness) const;
459434

435+
/// Apply the given function object to each value witness within this
436+
/// protocol conformance.
437+
///
438+
/// The function object should accept a \c ValueDecl* for the requirement
439+
/// followed by the \c Witness for the witness. Note that a generic
440+
/// witness will only be specialized if the conformance came from the current
441+
/// file.
442+
template<typename F>
443+
void forEachValueWitness(LazyResolver *resolver, F f) const {
444+
const ProtocolDecl *protocol = getProtocol();
445+
for (auto req : protocol->getMembers()) {
446+
auto valueReq = dyn_cast<ValueDecl>(req);
447+
if (!valueReq || isa<AssociatedTypeDecl>(valueReq) ||
448+
valueReq->isInvalid())
449+
continue;
450+
451+
if (!valueReq->isProtocolRequirement())
452+
continue;
453+
454+
// If we don't have and cannot resolve witnesses, skip it.
455+
if (!resolver && !hasWitness(valueReq))
456+
continue;
457+
458+
f(valueReq, getWitness(valueReq, resolver));
459+
}
460+
}
461+
460462
/// Retrieve the protocol conformances that satisfy the requirements of the
461463
/// protocol, which line up with the conformance constraints in the
462464
/// protocol's requirement signature.
@@ -565,10 +567,6 @@ class SpecializedProtocolConformance : public ProtocolConformance,
565567
getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
566568
LazyResolver *resolver) const;
567569

568-
/// Retrieve the value witness corresponding to the given requirement.
569-
Witness getWitness(ValueDecl *requirement, LazyResolver *resolver) const;
570-
571-
572570
/// Given that the requirement signature of the protocol directly states
573571
/// that the given dependent type must conform to the given protocol,
574572
/// return its associated conformance.
@@ -665,12 +663,6 @@ class InheritedProtocolConformance : public ProtocolConformance,
665663
return InheritedConformance->getTypeWitnessAndDecl(assocType, resolver);
666664
}
667665

668-
/// Retrieve the value witness corresponding to the given requirement.
669-
Witness getWitness(ValueDecl *requirement, LazyResolver *resolver) const {
670-
// FIXME: Substitute!
671-
return InheritedConformance->getWitness(requirement, resolver);
672-
}
673-
674666
/// Given that the requirement signature of the protocol directly states
675667
/// that the given dependent type must conform to the given protocol,
676668
/// return its associated conformance.

lib/AST/ConformanceLookupTable.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1103,7 +1103,8 @@ ConformanceLookupTable::getSatisfiedProtocolRequirementsForMember(
11031103
if (conf->isInvalid())
11041104
continue;
11051105

1106-
conf->forEachValueWitness(resolver, [&](ValueDecl *req,
1106+
auto normal = conf->getRootNormalConformance();
1107+
normal->forEachValueWitness(resolver, [&](ValueDecl *req,
11071108
ConcreteDeclRef witness) {
11081109
if (witness.getDecl() == member)
11091110
reqs.push_back(req);

lib/AST/ProtocolConformance.cpp

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -251,9 +251,22 @@ Type ProtocolConformance::getTypeWitness(AssociatedTypeDecl *assocType,
251251
return getTypeWitnessAndDecl(assocType, resolver).first;
252252
}
253253

254-
Witness ProtocolConformance::getWitness(ValueDecl *requirement,
255-
LazyResolver *resolver) const {
256-
CONFORMANCE_SUBCLASS_DISPATCH(getWitness, (requirement, resolver))
254+
ValueDecl *ProtocolConformance::getWitnessDecl(ValueDecl *requirement,
255+
LazyResolver *resolver) const {
256+
switch (getKind()) {
257+
case ProtocolConformanceKind::Normal:
258+
return cast<NormalProtocolConformance>(this)->getWitness(requirement,
259+
resolver)
260+
.getDecl();
261+
262+
case ProtocolConformanceKind::Inherited:
263+
return cast<InheritedProtocolConformance>(this)
264+
->getInheritedConformance()->getWitnessDecl(requirement, resolver);
265+
266+
case ProtocolConformanceKind::Specialized:
267+
return cast<SpecializedProtocolConformance>(this)
268+
->getGenericConformance()->getWitnessDecl(requirement, resolver);
269+
}
257270
}
258271

259272
/// Determine whether the witness for the given requirement
@@ -704,13 +717,6 @@ SpecializedProtocolConformance::getTypeWitnessAndDecl(
704717
return TypeWitnesses[assocType];
705718
}
706719

707-
Witness
708-
SpecializedProtocolConformance::getWitness(ValueDecl *requirement,
709-
LazyResolver *resolver) const {
710-
// FIXME: Apply substitutions here!
711-
return GenericConformance->getWitness(requirement, resolver);
712-
}
713-
714720
ProtocolConformanceRef
715721
SpecializedProtocolConformance::getAssociatedConformance(Type assocType,
716722
ProtocolDecl *protocol,

lib/SILGen/SILGenBridging.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ emitBridgeNativeToObjectiveC(SILGenFunction &SGF,
4444
if (!requirement) return None;
4545

4646
// Retrieve the _bridgeToObjectiveC witness.
47-
auto witness = conformance->getWitness(requirement, nullptr);
47+
auto witness = conformance->getWitnessDecl(requirement, nullptr);
4848
assert(witness);
4949

5050
// Determine the type we're bridging to.
@@ -55,7 +55,7 @@ emitBridgeNativeToObjectiveC(SILGenFunction &SGF,
5555
assert(objcType);
5656

5757
// Create a reference to the witness.
58-
SILDeclRef witnessConstant(witness.getDecl());
58+
SILDeclRef witnessConstant(witness);
5959
auto witnessRef = SGF.emitGlobalFunctionRef(loc, witnessConstant);
6060

6161
// Determine the substitutions.
@@ -65,10 +65,10 @@ emitBridgeNativeToObjectiveC(SILGenFunction &SGF,
6565

6666
// FIXME: Figure out the right SubstitutionMap stuff if the witness
6767
// has generic parameters of its own.
68-
assert(!cast<FuncDecl>(witness.getDecl())->isGeneric() &&
68+
assert(!cast<FuncDecl>(witness)->isGeneric() &&
6969
"Generic witnesses not supported");
7070

71-
auto *dc = cast<FuncDecl>(witness.getDecl())->getDeclContext();
71+
auto *dc = cast<FuncDecl>(witness)->getDeclContext();
7272
auto *genericSig = dc->getGenericSignatureOfContext();
7373
auto typeSubMap = swiftValueType->getContextSubstitutionMap(
7474
SGF.SGM.SwiftModule, dc);
@@ -118,11 +118,11 @@ emitBridgeObjectiveCToNative(SILGenFunction &SGF,
118118
if (!requirement) return None;
119119

120120
// Retrieve the _unconditionallyBridgeFromObjectiveC witness.
121-
auto witness = conformance->getWitness(requirement, nullptr);
121+
auto witness = conformance->getWitnessDecl(requirement, nullptr);
122122
assert(witness);
123123

124124
// Create a reference to the witness.
125-
SILDeclRef witnessConstant(witness.getDecl());
125+
SILDeclRef witnessConstant(witness);
126126
auto witnessRef = SGF.emitGlobalFunctionRef(loc, witnessConstant);
127127

128128
// Determine the substitutions.

lib/SILGen/SILGenConvert.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -483,10 +483,12 @@ ManagedValue SILGenFunction::emitExistentialErasure(
483483
// Devirtualize. Maybe this should be done implicitly by
484484
// emitPropertyLValue?
485485
if (storedNSErrorConformance->isConcrete()) {
486-
if (auto witnessVar = storedNSErrorConformance->getConcrete()
487-
->getWitness(nsErrorVar, nullptr)) {
488-
nsErrorVar = cast<VarDecl>(witnessVar.getDecl());
489-
nsErrorVarSubstitutions = witnessVar.getSubstitutions();
486+
if (auto normal = dyn_cast<NormalProtocolConformance>(
487+
storedNSErrorConformance->getConcrete())) {
488+
if (auto witnessVar = normal->getWitness(nsErrorVar, nullptr)) {
489+
nsErrorVar = cast<VarDecl>(witnessVar.getDecl());
490+
nsErrorVarSubstitutions = witnessVar.getSubstitutions();
491+
}
490492
}
491493
}
492494

lib/Sema/CSApply.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ static DeclTy *findNamedWitnessImpl(
166166
return requirement;
167167
auto concrete = conformance->getConcrete();
168168
// FIXME: Dropping substitutions here.
169-
return cast_or_null<DeclTy>(concrete->getWitness(requirement, &tc).getDecl());
169+
return cast_or_null<DeclTy>(concrete->getWitnessDecl(requirement, &tc));
170170
}
171171

172172
static bool shouldAccessStorageDirectly(Expr *base, VarDecl *member,
@@ -426,16 +426,15 @@ namespace {
426426
(ConformanceCheckFlags::InExpression|
427427
ConformanceCheckFlags::Used));
428428
if (conformance && conformance->isConcrete()) {
429-
if (auto witnessRef =
430-
conformance->getConcrete()->getWitness(decl, &tc)) {
429+
if (auto witness =
430+
conformance->getConcrete()->getWitnessDecl(decl, &tc)) {
431431
// Hack up an AST that we can type-check (independently) to get
432432
// it into the right form.
433433
// FIXME: the hop through 'getDecl()' is because
434434
// SpecializedProtocolConformance doesn't substitute into
435435
// witnesses' ConcreteDeclRefs.
436436
Type expectedFnType = simplifiedFnType->getResult();
437437
Expr *refExpr;
438-
ValueDecl *witness = witnessRef.getDecl();
439438
if (witness->getDeclContext()->isTypeContext()) {
440439
Expr *base =
441440
TypeExpr::createImplicitHack(loc.getBaseNameLoc(), baseTy,

lib/Sema/CSRanking.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,7 @@ static Comparison compareWitnessAndRequirement(TypeChecker &tc, DeclContext *dc,
200200

201201
// If the witness and the potential witness are not the same, there's no
202202
// ordering here.
203-
if (conformance->getConcrete()->getWitness(req, &tc).getDecl()
204-
!= potentialWitness)
203+
if (conformance->getConcrete()->getWitnessDecl(req, &tc) != potentialWitness)
205204
return Comparison::Unordered;
206205

207206
// We have a requirement/witness match.

lib/Sema/TypeCheckNameLookup.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ namespace {
155155
witness = concrete->getTypeWitnessAndDecl(assocType, &TC)
156156
.second;
157157
} else if (found->isProtocolRequirement()) {
158-
witness = concrete->getWitness(found, &TC).getDecl();
158+
witness = concrete->getWitnessDecl(found, &TC);
159159
}
160160

161161
// FIXME: the "isa<ProtocolDecl>()" check will be wrong for

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2696,7 +2696,7 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
26962696
if (auto conformance =
26972697
TC.conformsToProtocol(Adoptee, derivableProto, DC, None)) {
26982698
if (conformance->isConcrete())
2699-
conformance->getConcrete()->getWitness(derivable, &TC);
2699+
(void)conformance->getConcrete()->getWitnessDecl(derivable, &TC);
27002700
}
27012701
}
27022702
}
@@ -5990,7 +5990,7 @@ TypeChecker::findWitnessedObjCRequirements(const ValueDecl *witness,
59905990
}
59915991
if (!*conformance) continue;
59925992

5993-
const Decl *found = (*conformance)->getWitness(req, this).getDecl();
5993+
const Decl *found = (*conformance)->getWitnessDecl(req, this);
59945994

59955995
if (!found) {
59965996
// If we have an optional requirement in an inherited conformance,

0 commit comments

Comments
 (0)