Skip to content

Commit 86f9ca7

Browse files
committed
AST: Add ProtocolConformanceRef::getWitnessByName()
1 parent 6e3609d commit 86f9ca7

File tree

3 files changed

+45
-76
lines changed

3 files changed

+45
-76
lines changed

include/swift/AST/ProtocolConformanceRef.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ namespace llvm {
2828

2929
namespace swift {
3030

31+
class ConcreteDeclRef;
3132
class ProtocolConformance;
3233

3334
/// A ProtocolConformanceRef is a handle to a protocol conformance which
@@ -137,6 +138,14 @@ class ProtocolConformanceRef {
137138

138139
Type getTypeWitnessByName(Type type, Identifier name) const;
139140

141+
/// Find a particular named function witness for a type that conforms to
142+
/// the given protocol.
143+
///
144+
/// \param type The conforming type.
145+
///
146+
/// \param name The name of the requirement.
147+
ConcreteDeclRef getWitnessByName(Type type, DeclName name) const;
148+
140149
/// Determine whether this conformance is canonical.
141150
bool isCanonical() const;
142151

lib/AST/ProtocolConformance.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,34 @@ ProtocolConformanceRef::getTypeWitnessByName(Type type, Identifier name) const {
164164
SubstitutionMap::getProtocolSubstitutions(proto, type, *this));
165165
}
166166

167+
ConcreteDeclRef
168+
ProtocolConformanceRef::getWitnessByName(Type type, DeclName name) const {
169+
// Find the named requirement.
170+
auto *proto = getRequirement();
171+
auto results =
172+
proto->lookupDirect(name,
173+
NominalTypeDecl::LookupDirectFlags::IgnoreNewExtensions);
174+
175+
ValueDecl *requirement = nullptr;
176+
for (auto *result : results) {
177+
if (isa<ProtocolDecl>(result->getDeclContext()))
178+
requirement = result;
179+
}
180+
181+
if (requirement == nullptr)
182+
return ConcreteDeclRef();
183+
184+
// For a type with dependent conformance, just return the requirement from
185+
// the protocol. There are no protocol conformance tables.
186+
if (!isConcrete()) {
187+
auto subs = SubstitutionMap::getProtocolSubstitutions(proto, type, *this);
188+
return ConcreteDeclRef(requirement, subs);
189+
}
190+
191+
auto *resolver = proto->getASTContext().getLazyResolver();
192+
return getConcrete()->getWitnessDeclRef(requirement, resolver);
193+
}
194+
167195
void *ProtocolConformance::operator new(size_t bytes, ASTContext &context,
168196
AllocationArena arena,
169197
unsigned alignment) {

lib/Sema/CSApply.cpp

Lines changed: 8 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -99,67 +99,6 @@ SubstitutionMap Solution::computeSubstitutions(
9999
lookupConformanceFn);
100100
}
101101

102-
/// Find a particular named function witness for a type that conforms to
103-
/// the given protocol.
104-
///
105-
/// \param tc The type check we're using.
106-
///
107-
/// \param dc The context in which we need a witness.
108-
///
109-
/// \param type The type whose witness to find.
110-
///
111-
/// \param proto The protocol to which the type conforms.
112-
///
113-
/// \param name The name of the requirement.
114-
///
115-
/// \param diag The diagnostic to emit if the protocol definition doesn't
116-
/// have a requirement with the given name.
117-
///
118-
/// \returns The named witness, or an empty ConcreteDeclRef if no witness
119-
/// could be found.
120-
ConcreteDeclRef findNamedWitnessImpl(
121-
TypeChecker &tc, DeclContext *dc, Type type,
122-
ProtocolDecl *proto, DeclName name,
123-
Diag<> diag,
124-
Optional<ProtocolConformanceRef> conformance = None) {
125-
// Find the named requirement.
126-
ValueDecl *requirement = nullptr;
127-
for (auto member : proto->getMembers()) {
128-
auto d = dyn_cast<ValueDecl>(member);
129-
if (!d || !d->hasName())
130-
continue;
131-
132-
if (d->getFullName().matchesRef(name)) {
133-
requirement = d;
134-
break;
135-
}
136-
}
137-
138-
if (!requirement || requirement->isInvalid()) {
139-
tc.diagnose(proto->getLoc(), diag);
140-
return nullptr;
141-
}
142-
143-
// Find the member used to satisfy the named requirement.
144-
if (!conformance) {
145-
conformance = tc.conformsToProtocol(type, proto, dc,
146-
ConformanceCheckFlags::InExpression);
147-
if (!conformance)
148-
return nullptr;
149-
}
150-
151-
// For a type with dependent conformance, just return the requirement from
152-
// the protocol. There are no protocol conformance tables.
153-
if (!conformance->isConcrete()) {
154-
auto subMap = SubstitutionMap::getProtocolSubstitutions(proto, type,
155-
*conformance);
156-
return ConcreteDeclRef(requirement, subMap);
157-
}
158-
159-
auto concrete = conformance->getConcrete();
160-
return concrete->getWitnessDeclRef(requirement, &tc);
161-
}
162-
163102
static bool shouldAccessStorageDirectly(Expr *base, VarDecl *member,
164103
DeclContext *DC) {
165104
// This only matters for stored properties.
@@ -2974,10 +2913,8 @@ namespace {
29742913

29752914
DeclName name(tc.Context, DeclBaseName::createConstructor(),
29762915
{ tc.Context.Id_arrayLiteral });
2977-
29782916
ConcreteDeclRef witness =
2979-
findNamedWitnessImpl(tc, dc, arrayTy->getRValueType(), arrayProto,
2980-
name, diag::array_protocol_broken, conformance);
2917+
conformance->getWitnessByName(arrayTy->getRValueType(), name);
29812918
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
29822919
return nullptr;
29832920
expr->setInitializer(witness);
@@ -6854,10 +6791,8 @@ Expr *ExprRewriter::convertLiteralInPlace(Expr *literal,
68546791

68556792
// Find the witness that we'll use to initialize the type via a builtin
68566793
// literal.
6857-
auto witness = findNamedWitnessImpl(
6858-
tc, dc, type->getRValueType(), builtinProtocol,
6859-
builtinLiteralFuncName, brokenBuiltinProtocolDiag,
6860-
*builtinConformance);
6794+
auto witness = builtinConformance->getWitnessByName(type->getRValueType(),
6795+
builtinLiteralFuncName);
68616796
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
68626797
return nullptr;
68636798

@@ -6905,10 +6840,8 @@ Expr *ExprRewriter::convertLiteralInPlace(Expr *literal,
69056840
}
69066841

69076842
// Find the witness that we'll use to initialize the literal value.
6908-
auto witness = findNamedWitnessImpl(
6909-
tc, dc, type->getRValueType(), protocol,
6910-
literalFuncName, brokenProtocolDiag,
6911-
conformance);
6843+
auto witness = conformance->getWitnessByName(type->getRValueType(),
6844+
literalFuncName);
69126845
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
69136846
return nullptr;
69146847

@@ -7752,10 +7685,9 @@ Expr *TypeChecker::callWitness(Expr *base, DeclContext *dc,
77527685

77537686
if (auto metaType = type->getAs<AnyMetatypeType>())
77547687
type = metaType->getInstanceType();
7755-
7756-
auto witness = findNamedWitnessImpl(
7757-
*this, dc, type->getRValueType(), protocol,
7758-
name, brokenProtocolDiag);
7688+
7689+
// Find the member used to satisfy the named requirement.
7690+
auto witness = conformance.getWitnessByName(type, name);
77597691
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
77607692
return nullptr;
77617693

0 commit comments

Comments
 (0)