Skip to content

Commit

Permalink
AST: Add ProtocolConformanceRef::getWitnessByName()
Browse files Browse the repository at this point in the history
  • Loading branch information
slavapestov committed May 15, 2019
1 parent 6e3609d commit 86f9ca7
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 76 deletions.
9 changes: 9 additions & 0 deletions include/swift/AST/ProtocolConformanceRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace llvm {

namespace swift {

class ConcreteDeclRef;
class ProtocolConformance;

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

Type getTypeWitnessByName(Type type, Identifier name) const;

/// Find a particular named function witness for a type that conforms to
/// the given protocol.
///
/// \param type The conforming type.
///
/// \param name The name of the requirement.
ConcreteDeclRef getWitnessByName(Type type, DeclName name) const;

/// Determine whether this conformance is canonical.
bool isCanonical() const;

Expand Down
28 changes: 28 additions & 0 deletions lib/AST/ProtocolConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,34 @@ ProtocolConformanceRef::getTypeWitnessByName(Type type, Identifier name) const {
SubstitutionMap::getProtocolSubstitutions(proto, type, *this));
}

ConcreteDeclRef
ProtocolConformanceRef::getWitnessByName(Type type, DeclName name) const {
// Find the named requirement.
auto *proto = getRequirement();
auto results =
proto->lookupDirect(name,
NominalTypeDecl::LookupDirectFlags::IgnoreNewExtensions);

ValueDecl *requirement = nullptr;
for (auto *result : results) {
if (isa<ProtocolDecl>(result->getDeclContext()))
requirement = result;
}

if (requirement == nullptr)
return ConcreteDeclRef();

// For a type with dependent conformance, just return the requirement from
// the protocol. There are no protocol conformance tables.
if (!isConcrete()) {
auto subs = SubstitutionMap::getProtocolSubstitutions(proto, type, *this);
return ConcreteDeclRef(requirement, subs);
}

auto *resolver = proto->getASTContext().getLazyResolver();
return getConcrete()->getWitnessDeclRef(requirement, resolver);
}

void *ProtocolConformance::operator new(size_t bytes, ASTContext &context,
AllocationArena arena,
unsigned alignment) {
Expand Down
84 changes: 8 additions & 76 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,67 +99,6 @@ SubstitutionMap Solution::computeSubstitutions(
lookupConformanceFn);
}

/// Find a particular named function witness for a type that conforms to
/// the given protocol.
///
/// \param tc The type check we're using.
///
/// \param dc The context in which we need a witness.
///
/// \param type The type whose witness to find.
///
/// \param proto The protocol to which the type conforms.
///
/// \param name The name of the requirement.
///
/// \param diag The diagnostic to emit if the protocol definition doesn't
/// have a requirement with the given name.
///
/// \returns The named witness, or an empty ConcreteDeclRef if no witness
/// could be found.
ConcreteDeclRef findNamedWitnessImpl(
TypeChecker &tc, DeclContext *dc, Type type,
ProtocolDecl *proto, DeclName name,
Diag<> diag,
Optional<ProtocolConformanceRef> conformance = None) {
// Find the named requirement.
ValueDecl *requirement = nullptr;
for (auto member : proto->getMembers()) {
auto d = dyn_cast<ValueDecl>(member);
if (!d || !d->hasName())
continue;

if (d->getFullName().matchesRef(name)) {
requirement = d;
break;
}
}

if (!requirement || requirement->isInvalid()) {
tc.diagnose(proto->getLoc(), diag);
return nullptr;
}

// Find the member used to satisfy the named requirement.
if (!conformance) {
conformance = tc.conformsToProtocol(type, proto, dc,
ConformanceCheckFlags::InExpression);
if (!conformance)
return nullptr;
}

// For a type with dependent conformance, just return the requirement from
// the protocol. There are no protocol conformance tables.
if (!conformance->isConcrete()) {
auto subMap = SubstitutionMap::getProtocolSubstitutions(proto, type,
*conformance);
return ConcreteDeclRef(requirement, subMap);
}

auto concrete = conformance->getConcrete();
return concrete->getWitnessDeclRef(requirement, &tc);
}

static bool shouldAccessStorageDirectly(Expr *base, VarDecl *member,
DeclContext *DC) {
// This only matters for stored properties.
Expand Down Expand Up @@ -2974,10 +2913,8 @@ namespace {

DeclName name(tc.Context, DeclBaseName::createConstructor(),
{ tc.Context.Id_arrayLiteral });

ConcreteDeclRef witness =
findNamedWitnessImpl(tc, dc, arrayTy->getRValueType(), arrayProto,
name, diag::array_protocol_broken, conformance);
conformance->getWitnessByName(arrayTy->getRValueType(), name);
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
return nullptr;
expr->setInitializer(witness);
Expand Down Expand Up @@ -6854,10 +6791,8 @@ Expr *ExprRewriter::convertLiteralInPlace(Expr *literal,

// Find the witness that we'll use to initialize the type via a builtin
// literal.
auto witness = findNamedWitnessImpl(
tc, dc, type->getRValueType(), builtinProtocol,
builtinLiteralFuncName, brokenBuiltinProtocolDiag,
*builtinConformance);
auto witness = builtinConformance->getWitnessByName(type->getRValueType(),
builtinLiteralFuncName);
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
return nullptr;

Expand Down Expand Up @@ -6905,10 +6840,8 @@ Expr *ExprRewriter::convertLiteralInPlace(Expr *literal,
}

// Find the witness that we'll use to initialize the literal value.
auto witness = findNamedWitnessImpl(
tc, dc, type->getRValueType(), protocol,
literalFuncName, brokenProtocolDiag,
conformance);
auto witness = conformance->getWitnessByName(type->getRValueType(),
literalFuncName);
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
return nullptr;

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

if (auto metaType = type->getAs<AnyMetatypeType>())
type = metaType->getInstanceType();

auto witness = findNamedWitnessImpl(
*this, dc, type->getRValueType(), protocol,
name, brokenProtocolDiag);

// Find the member used to satisfy the named requirement.
auto witness = conformance.getWitnessByName(type, name);
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
return nullptr;

Expand Down

0 comments on commit 86f9ca7

Please sign in to comment.