Merge remote-tracking branch 'origin/main' into rebranch

This commit is contained in:
swift-ci
2022-08-09 20:55:09 -07:00
12 changed files with 68 additions and 81 deletions

View File

@@ -49,7 +49,7 @@ thunk helpers" sometimes seen in Swift backtraces come from.)
Broadly, an "access path" is a list of "accesses" which must be chained together Broadly, an "access path" is a list of "accesses" which must be chained together
to compute some output from an input. For instance, the generics system has a to compute some output from an input. For instance, the generics system has a
type called a `ConformanceAccessPath` which explains how to, for example, type called a `ConformancePath` which explains how to, for example,
walk from `T: Collection` to `T: Sequence` to `T.Iterator: IteratorProtocol`. walk from `T: Collection` to `T: Sequence` to `T.Iterator: IteratorProtocol`.
There are several different kinds of "access path" in different parts of the compiler, There are several different kinds of "access path" in different parts of the compiler,
but they all follow this basic theme. but they all follow this basic theme.

View File

@@ -25,7 +25,7 @@ class NamedDecl;
namespace swift { namespace swift {
class AbstractClosureExpr; class AbstractClosureExpr;
class ConformanceAccessPath; class ConformancePath;
class RootProtocolConformance; class RootProtocolConformance;
namespace Mangle { namespace Mangle {
@@ -560,7 +560,7 @@ protected:
void appendConcreteProtocolConformance( void appendConcreteProtocolConformance(
const ProtocolConformance *conformance, const ProtocolConformance *conformance,
GenericSignature sig); GenericSignature sig);
void appendDependentProtocolConformance(const ConformanceAccessPath &path, void appendDependentProtocolConformance(const ConformancePath &path,
GenericSignature sig); GenericSignature sig);
void appendOpParamForLayoutConstraint(LayoutConstraint Layout); void appendOpParamForLayoutConstraint(LayoutConstraint Layout);

View File

@@ -70,7 +70,7 @@ namespace rewriting {
/// \c Sequence conformance of \c C (because \c Collection inherits /// \c Sequence conformance of \c C (because \c Collection inherits
/// \c Sequence). Finally, it extracts the conformance of the associated type /// \c Sequence). Finally, it extracts the conformance of the associated type
/// \c Iterator to \c IteratorProtocol from the \c Sequence protocol. /// \c Iterator to \c IteratorProtocol from the \c Sequence protocol.
class ConformanceAccessPath { class ConformancePath {
public: public:
/// An entry in the conformance access path, which is described by the /// An entry in the conformance access path, which is described by the
/// dependent type on which the conformance is stated as the protocol to /// dependent type on which the conformance is stated as the protocol to
@@ -80,7 +80,7 @@ public:
private: private:
ArrayRef<Entry> path; ArrayRef<Entry> path;
ConformanceAccessPath(ArrayRef<Entry> path) : path(path) {} ConformancePath(ArrayRef<Entry> path) : path(path) {}
friend class GenericSignatureImpl; friend class GenericSignatureImpl;
friend class rewriting::RequirementMachine; friend class rewriting::RequirementMachine;
@@ -398,20 +398,20 @@ public:
/// signature. /// signature.
bool isValidTypeParameter(Type type) const; bool isValidTypeParameter(Type type) const;
/// Retrieve the conformance access path used to extract the conformance of /// Retrieve the conformance path used to extract the conformance of
/// interface \c type to the given \c protocol. /// interface \c type to the given \c protocol.
/// ///
/// \param type The interface type whose conformance access path is to be /// \param type The type parameter whose conformance path is to be
/// queried. /// queried.
/// \param protocol A protocol to which \c type conforms. /// \param protocol A protocol to which \c type conforms.
/// ///
/// \returns the conformance access path that starts at a requirement of /// \returns the conformance path that starts at a requirement of
/// this generic signature and ends at the conformance that makes \c type /// this generic signature and ends at the conformance that makes \c type
/// conform to \c protocol. /// conform to \c protocol.
/// ///
/// \seealso ConformanceAccessPath /// \seealso ConformancePath
ConformanceAccessPath getConformanceAccessPath(Type type, ConformancePath getConformancePath(Type type,
ProtocolDecl *protocol) const; ProtocolDecl *protocol) const;
/// Lookup a nested type with the given name within this type parameter. /// Lookup a nested type with the given name within this type parameter.
TypeDecl *lookupNestedType(Type type, Identifier name) const; TypeDecl *lookupNestedType(Type type, Identifier name) const;

View File

@@ -230,16 +230,8 @@ FRONTEND_STATISTIC(Sema, NumRequirementMachineCompletionSteps)
/// Number of new rules added by concrete term unification. /// Number of new rules added by concrete term unification.
FRONTEND_STATISTIC(Sema, NumRequirementMachineUnifiedConcreteTerms) FRONTEND_STATISTIC(Sema, NumRequirementMachineUnifiedConcreteTerms)
/// Number of generic signature builders constructed. Rough proxy for /// Number of conformance paths we had to compute.
/// amount of work the GSB does analyzing type signatures. FRONTEND_STATISTIC(Sema, NumConformancePathsRecorded)
FRONTEND_STATISTIC(Sema, NumGenericSignatureBuilders)
/// Number of steps in the GSB's redundant requirements algorithm, which is in
/// the worst-case exponential.
FRONTEND_STATISTIC(Sema, NumRedundantRequirementSteps)
/// Number of conformance access paths we had to compute.
FRONTEND_STATISTIC(Sema, NumConformanceAccessPathsRecorded)
/// Number of lazy requirement signatures registered. /// Number of lazy requirement signatures registered.
FRONTEND_STATISTIC(Sema, NumLazyRequirementSignatures) FRONTEND_STATISTIC(Sema, NumLazyRequirementSignatures)

View File

@@ -3357,9 +3357,9 @@ void ASTMangler::appendProtocolConformanceRef(
} }
/// Retrieve the index of the conformance requirement indicated by the /// Retrieve the index of the conformance requirement indicated by the
/// conformance access path entry within the given set of requirements. /// conformance path entry within the given set of requirements.
static unsigned conformanceRequirementIndex( static unsigned conformanceRequirementIndex(
const ConformanceAccessPath::Entry &entry, const ConformancePath::Entry &entry,
ArrayRef<Requirement> requirements) { ArrayRef<Requirement> requirements) {
unsigned result = 0; unsigned result = 0;
for (const auto &req : requirements) { for (const auto &req : requirements) {
@@ -3377,7 +3377,7 @@ static unsigned conformanceRequirementIndex(
} }
void ASTMangler::appendDependentProtocolConformance( void ASTMangler::appendDependentProtocolConformance(
const ConformanceAccessPath &path, const ConformancePath &path,
GenericSignature sig) { GenericSignature sig) {
ProtocolDecl *currentProtocol = nullptr; ProtocolDecl *currentProtocol = nullptr;
for (const auto &entry : path) { for (const auto &entry : path) {
@@ -3441,19 +3441,19 @@ void ASTMangler::appendAnyProtocolConformance(
if (conformingType->isTypeParameter()) { if (conformingType->isTypeParameter()) {
assert(genericSig && "Need a generic signature to resolve conformance"); assert(genericSig && "Need a generic signature to resolve conformance");
auto path = genericSig->getConformanceAccessPath(conformingType, auto path = genericSig->getConformancePath(conformingType,
conformance.getAbstract()); conformance.getAbstract());
appendDependentProtocolConformance(path, genericSig); appendDependentProtocolConformance(path, genericSig);
} else if (auto opaqueType = conformingType->getAs<OpaqueTypeArchetypeType>()) { } else if (auto opaqueType = conformingType->getAs<OpaqueTypeArchetypeType>()) {
GenericSignature opaqueSignature = GenericSignature opaqueSignature =
opaqueType->getDecl()->getOpaqueInterfaceGenericSignature(); opaqueType->getDecl()->getOpaqueInterfaceGenericSignature();
ConformanceAccessPath conformanceAccessPath = ConformancePath conformancePath =
opaqueSignature->getConformanceAccessPath( opaqueSignature->getConformancePath(
opaqueType->getInterfaceType(), opaqueType->getInterfaceType(),
conformance.getAbstract()); conformance.getAbstract());
// Append the conformance access path with the signature of the opaque type. // Append the conformance path with the signature of the opaque type.
appendDependentProtocolConformance(conformanceAccessPath, opaqueSignature); appendDependentProtocolConformance(conformancePath, opaqueSignature);
appendType(conformingType, genericSig); appendType(conformingType, genericSig);
appendOperator("HO"); appendOperator("HO");
} else { } else {

View File

@@ -29,7 +29,7 @@
using namespace swift; using namespace swift;
void ConformanceAccessPath::print(raw_ostream &out) const { void ConformancePath::print(raw_ostream &out) const {
llvm::interleave( llvm::interleave(
begin(), end(), begin(), end(),
[&](const Entry &entry) { [&](const Entry &entry) {
@@ -39,7 +39,7 @@ void ConformanceAccessPath::print(raw_ostream &out) const {
[&] { out << " -> "; }); [&] { out << " -> "; });
} }
void ConformanceAccessPath::dump() const { void ConformancePath::dump() const {
print(llvm::errs()); print(llvm::errs());
llvm::errs() << "\n"; llvm::errs() << "\n";
} }
@@ -475,10 +475,10 @@ CanGenericSignature::getGenericParams() const {
return {base, params.size()}; return {base, params.size()};
} }
ConformanceAccessPath ConformancePath
GenericSignatureImpl::getConformanceAccessPath(Type type, GenericSignatureImpl::getConformancePath(Type type,
ProtocolDecl *protocol) const { ProtocolDecl *protocol) const {
return getRequirementMachine()->getConformanceAccessPath(type, protocol); return getRequirementMachine()->getConformancePath(type, protocol);
} }
TypeDecl * TypeDecl *

View File

@@ -28,7 +28,7 @@
// arbitrary type, not just a type parameter, and recursively transfozms the // arbitrary type, not just a type parameter, and recursively transfozms the
// type parameters it contains, if any. // type parameters it contains, if any.
// //
// Also, getConformanceAccessPath() is another one-off operation. // Also, getConformancePath() is another one-off operation.
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@@ -469,7 +469,7 @@ bool RequirementMachine::isValidTypeParameter(Type type) const {
return (prefix == term); return (prefix == term);
} }
/// Retrieve the conformance access path used to extract the conformance of /// Retrieve the conformance path used to extract the conformance of
/// interface \c type to the given \c protocol. /// interface \c type to the given \c protocol.
/// ///
/// \param type The interface type whose conformance access path is to be /// \param type The interface type whose conformance access path is to be
@@ -480,10 +480,10 @@ bool RequirementMachine::isValidTypeParameter(Type type) const {
/// this generic signature and ends at the conformance that makes \c type /// this generic signature and ends at the conformance that makes \c type
/// conform to \c protocol. /// conform to \c protocol.
/// ///
/// \seealso ConformanceAccessPath /// \seealso ConformancePath
ConformanceAccessPath ConformancePath
RequirementMachine::getConformanceAccessPath(Type type, RequirementMachine::getConformancePath(Type type,
ProtocolDecl *protocol) { ProtocolDecl *protocol) {
assert(type->isTypeParameter()); assert(type->isTypeParameter());
auto mutTerm = Context.getMutableTermForType(type->getCanonicalType(), auto mutTerm = Context.getMutableTermForType(type->getCanonicalType(),
@@ -505,9 +505,9 @@ RequirementMachine::getConformanceAccessPath(Type type,
auto term = Term::get(mutTerm, Context); auto term = Term::get(mutTerm, Context);
// Check if we've already cached the result before doing anything else. // Check if we've already cached the result before doing anything else.
auto found = ConformanceAccessPaths.find( auto found = ConformancePaths.find(
std::make_pair(term, protocol)); std::make_pair(term, protocol));
if (found != ConformanceAccessPaths.end()) { if (found != ConformancePaths.end()) {
return found->second; return found->second;
} }
@@ -516,25 +516,25 @@ RequirementMachine::getConformanceAccessPath(Type type,
FrontendStatsTracer tracer(Stats, "get-conformance-access-path"); FrontendStatsTracer tracer(Stats, "get-conformance-access-path");
auto recordPath = [&](Term term, ProtocolDecl *proto, auto recordPath = [&](Term term, ProtocolDecl *proto,
ConformanceAccessPath path) { ConformancePath path) {
// Add the path to the buffer. // Add the path to the buffer.
CurrentConformanceAccessPaths.emplace_back(term, path); CurrentConformancePaths.emplace_back(term, path);
// Add the path to the map. // Add the path to the map.
auto key = std::make_pair(term, proto); auto key = std::make_pair(term, proto);
auto inserted = ConformanceAccessPaths.insert( auto inserted = ConformancePaths.insert(
std::make_pair(key, path)); std::make_pair(key, path));
assert(inserted.second); assert(inserted.second);
(void) inserted; (void) inserted;
if (Stats) if (Stats)
++Stats->getFrontendCounters().NumConformanceAccessPathsRecorded; ++Stats->getFrontendCounters().NumConformancePathsRecorded;
}; };
// If this is the first time we're asked to look up a conformance access path, // If this is the first time we're asked to look up a conformance access path,
// visit all of the root conformance requirements in our generic signature and // visit all of the root conformance requirements in our generic signature and
// add them to the buffer. // add them to the buffer.
if (ConformanceAccessPaths.empty()) { if (ConformancePaths.empty()) {
for (const auto &req : Sig.getRequirements()) { for (const auto &req : Sig.getRequirements()) {
// We only care about conformance requirements. // We only care about conformance requirements.
if (req.getKind() != RequirementKind::Conformance) if (req.getKind() != RequirementKind::Conformance)
@@ -543,9 +543,9 @@ RequirementMachine::getConformanceAccessPath(Type type,
auto rootType = CanType(req.getFirstType()); auto rootType = CanType(req.getFirstType());
auto *rootProto = req.getProtocolDecl(); auto *rootProto = req.getProtocolDecl();
ConformanceAccessPath::Entry root(rootType, rootProto); ConformancePath::Entry root(rootType, rootProto);
ArrayRef<ConformanceAccessPath::Entry> path(root); ArrayRef<ConformancePath::Entry> path(root);
ConformanceAccessPath result(ctx.AllocateCopy(path)); ConformancePath result(ctx.AllocateCopy(path));
auto mutTerm = Context.getMutableTermForType(rootType, nullptr); auto mutTerm = Context.getMutableTermForType(rootType, nullptr);
System.simplify(mutTerm); System.simplify(mutTerm);
@@ -555,17 +555,17 @@ RequirementMachine::getConformanceAccessPath(Type type,
} }
} }
// We enumerate conformance access paths in shortlex order until we find the // We enumerate conformance paths in shortlex order until we find the
// path whose corresponding type reduces to the one we are looking for. // path whose corresponding type reduces to the one we are looking for.
while (true) { while (true) {
auto found = ConformanceAccessPaths.find( auto found = ConformancePaths.find(
std::make_pair(term, protocol)); std::make_pair(term, protocol));
if (found != ConformanceAccessPaths.end()) { if (found != ConformancePaths.end()) {
return found->second; return found->second;
} }
if (CurrentConformanceAccessPaths.empty()) { if (CurrentConformancePaths.empty()) {
llvm::errs() << "Failed to find conformance access path for "; llvm::errs() << "Failed to find conformance path for ";
llvm::errs() << type << " (" << term << ")" << " : "; llvm::errs() << type << " (" << term << ")" << " : ";
llvm::errs() << protocol->getName() << ":\n"; llvm::errs() << protocol->getName() << ":\n";
type.dump(llvm::errs()); type.dump(llvm::errs());
@@ -574,18 +574,18 @@ RequirementMachine::getConformanceAccessPath(Type type,
abort(); abort();
} }
// The buffer consists of all conformance access paths of length N. // The buffer consists of all conformance paths of length N.
// Swap it out with an empty buffer, and fill it with all paths of // Swap it out with an empty buffer, and fill it with all paths of
// length N+1. // length N+1.
std::vector<std::pair<Term, ConformanceAccessPath>> oldPaths; std::vector<std::pair<Term, ConformancePath>> oldPaths;
std::swap(CurrentConformanceAccessPaths, oldPaths); std::swap(CurrentConformancePaths, oldPaths);
for (const auto &pair : oldPaths) { for (const auto &pair : oldPaths) {
const auto &lastElt = pair.second.back(); const auto &lastElt = pair.second.back();
auto *lastProto = lastElt.second; auto *lastProto = lastElt.second;
// A copy of the current path, populated as needed. // A copy of the current path, populated as needed.
SmallVector<ConformanceAccessPath::Entry, 4> entries; SmallVector<ConformancePath::Entry, 4> entries;
auto reqs = lastProto->getRequirementSignature().getRequirements(); auto reqs = lastProto->getRequirementSignature().getRequirements();
for (const auto &req : reqs) { for (const auto &req : reqs) {
@@ -607,7 +607,7 @@ RequirementMachine::getConformanceAccessPath(Type type,
// don't add it to the buffer. Note that because we iterate over // don't add it to the buffer. Note that because we iterate over
// conformance access paths in shortlex order, the existing // conformance access paths in shortlex order, the existing
// conformance access path is shorter than the one we found just now. // conformance access path is shorter than the one we found just now.
if (ConformanceAccessPaths.count( if (ConformancePaths.count(
std::make_pair(nextTerm, nextProto))) std::make_pair(nextTerm, nextProto)))
continue; continue;
@@ -620,7 +620,7 @@ RequirementMachine::getConformanceAccessPath(Type type,
// Add the next entry. // Add the next entry.
entries.emplace_back(nextSubjectType, nextProto); entries.emplace_back(nextSubjectType, nextProto);
ConformanceAccessPath result = ctx.AllocateCopy(entries); ConformancePath result = ctx.AllocateCopy(entries);
entries.pop_back(); entries.pop_back();
recordPath(nextTerm, nextProto, result); recordPath(nextTerm, nextProto, result);

View File

@@ -565,8 +565,8 @@ void RequirementMachine::dump(llvm::raw_ostream &out) const {
System.dump(out); System.dump(out);
Map.dump(out); Map.dump(out);
out << "Conformance access paths: {\n"; out << "Conformance paths: {\n";
for (auto pair : ConformanceAccessPaths) { for (auto pair : ConformancePaths) {
out << "- " << pair.first.first << " : "; out << "- " << pair.first.first << " : ";
out << pair.first.second->getName() << " => "; out << pair.first.second->getName() << " => ";
pair.second.print(out); pair.second.print(out);

View File

@@ -71,16 +71,15 @@ class RequirementMachine final {
UnifiedStatsReporter *Stats; UnifiedStatsReporter *Stats;
/// All conformance access paths computed so far. /// All conformance paths computed so far.
llvm::DenseMap<std::pair<Term, ProtocolDecl *>, llvm::DenseMap<std::pair<Term, ProtocolDecl *>,
ConformanceAccessPath> ConformanceAccessPaths; ConformancePath> ConformancePaths;
/// Conformance access paths computed during the last round. All elements /// Conformance access paths computed during the last round. All elements
/// have the same length. If a conformance access path of greater length /// have the same length. If a conformance access path of greater length
/// is requested, we refill CurrentConformanceAccessPaths with all paths of /// is requested, we refill CurrentConformancePaths with all paths of
/// length N+1, and add them to the ConformanceAccessPaths map. /// length N+1, and add them to the ConformancePaths map.
std::vector<std::pair<Term, ConformanceAccessPath>> std::vector<std::pair<Term, ConformancePath>> CurrentConformancePaths;
CurrentConformanceAccessPaths;
explicit RequirementMachine(RewriteContext &rewriteCtx); explicit RequirementMachine(RewriteContext &rewriteCtx);
@@ -158,8 +157,7 @@ public:
Type getReducedType(Type type, Type getReducedType(Type type,
TypeArrayView<GenericTypeParamType> genericParams) const; TypeArrayView<GenericTypeParamType> genericParams) const;
bool isValidTypeParameter(Type type) const; bool isValidTypeParameter(Type type) const;
ConformanceAccessPath getConformanceAccessPath(Type type, ConformancePath getConformancePath(Type type, ProtocolDecl *protocol);
ProtocolDecl *protocol);
TypeDecl *lookupNestedType(Type depType, Identifier name) const; TypeDecl *lookupNestedType(Type depType, Identifier name) const;
llvm::DenseMap<const ProtocolDecl *, RequirementSignature> llvm::DenseMap<const ProtocolDecl *, RequirementSignature>

View File

@@ -482,7 +482,7 @@ RequirementMachine::computeMinimalGenericSignature(
auto sig = GenericSignature::get(getGenericParams(), reqs); auto sig = GenericSignature::get(getGenericParams(), reqs);
// Remember the signature for generic signature queries. In particular, // Remember the signature for generic signature queries. In particular,
// getConformanceAccessPath() needs the current requirement machine's // getConformancePath() needs the current requirement machine's
// generic signature. // generic signature.
Sig = sig.getCanonicalSignature(); Sig = sig.getCanonicalSignature();

View File

@@ -367,11 +367,10 @@ SubstitutionMap::lookupConformance(CanType type, ProtocolDecl *proto) const {
return ProtocolConformanceRef::forMissingOrInvalid(substType, proto); return ProtocolConformanceRef::forMissingOrInvalid(substType, proto);
} }
auto accessPath = auto path = genericSig->getConformancePath(type, proto);
genericSig->getConformanceAccessPath(type, proto);
ProtocolConformanceRef conformance; ProtocolConformanceRef conformance;
for (const auto &step : accessPath) { for (const auto &step : path) {
// For the first step, grab the initial conformance. // For the first step, grab the initial conformance.
if (conformance.isInvalid()) { if (conformance.isInvalid()) {
if (auto initialConformance = getSignatureConformance( if (auto initialConformance = getSignatureConformance(

View File

@@ -191,8 +191,7 @@ llvm::Value *irgen::emitArchetypeWitnessTableRef(IRGenFunction &IGF,
auto environment = archetype->getGenericEnvironment(); auto environment = archetype->getGenericEnvironment();
// Otherwise, ask the generic signature for the environment for the best // Otherwise, ask the generic signature for the best path to the conformance.
// path to the conformance.
// TODO: this isn't necessarily optimal if the direct conformance isn't // TODO: this isn't necessarily optimal if the direct conformance isn't
// concretely available; we really ought to be comparing the full paths // concretely available; we really ought to be comparing the full paths
// to this conformance from concrete sources. // to this conformance from concrete sources.
@@ -200,8 +199,7 @@ llvm::Value *irgen::emitArchetypeWitnessTableRef(IRGenFunction &IGF,
auto signature = environment->getGenericSignature().getCanonicalSignature(); auto signature = environment->getGenericSignature().getCanonicalSignature();
auto archetypeDepType = archetype->getInterfaceType(); auto archetypeDepType = archetype->getInterfaceType();
auto astPath = signature->getConformanceAccessPath(archetypeDepType, auto astPath = signature->getConformancePath(archetypeDepType, protocol);
protocol);
auto i = astPath.begin(), e = astPath.end(); auto i = astPath.begin(), e = astPath.end();
assert(i != e && "empty path!"); assert(i != e && "empty path!");