Files
swift-mirror/lib/AST/GenericSignatureBuilder.cpp
Slava Pestov 87cf15a85d GSB: Replace some resolveDependentMemberTypes() calls with getCanonicalTypeInContext()
For now this has no effect since resolveDependentMemberTypes() maps
type parameters to anchors, but I'm going to change it to not do
that.

Change all existing callers of resolveDependentMemberTypes() except
for the one in maybeResolveEquivalenceClass() to use
getCanonicalTypeInContext() instead.
2021-03-24 18:45:04 -04:00

8811 lines
317 KiB
C++

//===--- GenericSignatureBuilder.cpp - Generic Requirement Builder --------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Support for collecting a set of generic requirements, both explicitly stated
// and inferred, and computing the archetypes and required witness tables from
// those requirements.
//
//===----------------------------------------------------------------------===//
#include "GenericSignatureBuilderImpl.h"
#include "swift/AST/GenericSignatureBuilder.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/DiagnosticsSema.h"
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/ExistentialLayout.h"
#include "swift/AST/FileUnit.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/GenericParamList.h"
#include "swift/AST/LazyResolver.h"
#include "swift/AST/Module.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/PrettyStackTrace.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/AST/TypeMatcher.h"
#include "swift/AST/TypeRepr.h"
#include "swift/AST/TypeWalker.h"
#include "swift/Basic/Debug.h"
#include "swift/Basic/Defer.h"
#include "swift/Basic/Statistic.h"
#include "llvm/ADT/GraphTraits.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/SaveAndRestore.h"
#include <algorithm>
using namespace swift;
using llvm::DenseMap;
/// Define this to 1 to enable expensive assertions.
#define SWIFT_GSB_EXPENSIVE_ASSERTIONS 0
namespace {
typedef GenericSignatureBuilder::RequirementSource RequirementSource;
typedef GenericSignatureBuilder::FloatingRequirementSource
FloatingRequirementSource;
typedef GenericSignatureBuilder::ConstraintResult ConstraintResult;
typedef GenericSignatureBuilder::PotentialArchetype PotentialArchetype;
typedef GenericSignatureBuilder::ConcreteConstraint ConcreteConstraint;
template<typename T> using Constraint =
GenericSignatureBuilder::Constraint<T>;
typedef GenericSignatureBuilder::EquivalenceClass EquivalenceClass;
typedef EquivalenceClass::DerivedSameTypeComponent DerivedSameTypeComponent;
typedef GenericSignatureBuilder::DelayedRequirement DelayedRequirement;
typedef GenericSignatureBuilder::ResolvedType ResolvedType;
typedef GenericSignatureBuilder::RequirementRHS RequirementRHS;
typedef GenericSignatureBuilder::ExplicitRequirement ExplicitRequirement;
} // end anonymous namespace
namespace llvm {
// Equivalence classes are bump-ptr-allocated.
template <> struct ilist_alloc_traits<EquivalenceClass> {
static void deleteNode(EquivalenceClass *ptr) { ptr->~EquivalenceClass(); }
};
}
#define DEBUG_TYPE "Generic signature builder"
STATISTIC(NumPotentialArchetypes, "# of potential archetypes");
STATISTIC(NumEquivalenceClassesAllocated, "# of equivalence classes allocated");
STATISTIC(NumEquivalenceClassesFreed, "# of equivalence classes freed");
STATISTIC(NumConformances, "# of conformances tracked");
STATISTIC(NumConformanceConstraints, "# of conformance constraints tracked");
STATISTIC(NumSameTypeConstraints, "# of same-type constraints tracked");
STATISTIC(NumConcreteTypeConstraints,
"# of same-type-to-concrete constraints tracked");
STATISTIC(NumSuperclassConstraints, "# of superclass constraints tracked");
STATISTIC(NumSuperclassConstraintsExtra,
"# of superclass constraints that add no information");
STATISTIC(NumLayoutConstraints, "# of layout constraints tracked");
STATISTIC(NumLayoutConstraintsExtra,
"# of layout constraints that add no information");
STATISTIC(NumSelfDerived, "# of self-derived constraints removed");
STATISTIC(NumArchetypeAnchorCacheHits,
"# of hits in the archetype anchor cache");
STATISTIC(NumArchetypeAnchorCacheMisses,
"# of misses in the archetype anchor cache");
STATISTIC(NumNestedTypeCacheHits,
"# of hits in the equivalence class nested type cache");
STATISTIC(NumNestedTypeCacheMisses,
"# of misses in the equivalence class nested type cache");
STATISTIC(NumProcessDelayedRequirements,
"# of times we process delayed requirements");
STATISTIC(NumProcessDelayedRequirementsUnchanged,
"# of times we process delayed requirements without change");
STATISTIC(NumDelayedRequirementConcrete,
"Delayed requirements resolved as concrete");
STATISTIC(NumDelayedRequirementResolved,
"Delayed requirements resolved");
STATISTIC(NumDelayedRequirementUnresolved,
"Delayed requirements left unresolved");
STATISTIC(NumConditionalRequirementsAdded,
"# of conditional requirements added");
STATISTIC(NumRewriteMinimizations,
"# of rewrite system minimizations performed");
STATISTIC(NumRewriteRhsSimplified,
"# of rewrite rule right-hand sides simplified");
STATISTIC(NumRewriteRhsSimplifiedToLhs,
"# of rewrite rule right-hand sides simplified to lhs (and removed)");
STATISTIC(NumRewriteRulesRedundant,
"# of rewrite rules that are redundant (and removed)");
STATISTIC(NumSignaturesRebuiltWithoutRedundantRequirements,
"# of generic signatures which had a concretized conformance requirement");
namespace {
/// A purely-relative rewrite path consisting of a (possibly empty)
/// sequence of associated type references.
using RelativeRewritePath = ArrayRef<AssociatedTypeDecl *>;
class AnchorPathCache;
/// Describes a rewrite path, which contains an optional base (generic
/// parameter) followed by a sequence of associated type references.
class RewritePath {
Optional<GenericParamKey> base;
TinyPtrVector<AssociatedTypeDecl *> path;
public:
RewritePath() { }
enum PathOrder {
Forward,
Reverse,
};
/// Form a rewrite path given an optional base and a relative rewrite path.
RewritePath(Optional<GenericParamKey> base, RelativeRewritePath path,
PathOrder order);
/// Retrieve the base of the given rewrite path.
///
/// When present, it indicates that the entire path will be rebased on
/// the given base generic parameter. This is required for describing
/// rewrites on type parameters themselves, e.g., T == U.
///
/// When absent, the path is relative to the root of the tree from which
/// the search began.
Optional<GenericParamKey> getBase() const { return base; }
/// Retrieve the sequence of associated type references that describes
/// the path.
ArrayRef<AssociatedTypeDecl *> getPath() const { return path; }
/// Whether this path is completely empty.
bool isEmpty() const { return getBase() == None && getPath().empty(); }
/// whether this describes a valid path.
explicit operator bool() const { return !isEmpty(); }
/// Decompose a type into a path.
///
/// \returns the path, or None if it contained unresolved dependent member
/// types.
static RewritePath createPath(Type type);
/// Decompose a type into a path.
///
/// \param path Will be filled in with the components of the path, in
/// reverse order.
///
/// \returns the generic parameter at the start of the path.
static GenericParamKey createPath(
Type type,
SmallVectorImpl<AssociatedTypeDecl *> &path);
/// Compute the longer common prefix between this path and \c other.
RewritePath commonPath(const RewritePath &other) const;
/// Form a canonical, dependent type.
///
/// This requires that either the rewrite path have a base, or the
/// \c baseEquivClass to be non-null (which substitutes in a base).
CanType formDependentType(ASTContext &ctx,
AnchorPathCache *anchorPathCache = nullptr) const;
/// Compare the given rewrite paths.
int compare(const RewritePath &other) const;
/// Print this path.
void print(llvm::raw_ostream &out) const;
SWIFT_DEBUG_DUMP {
print(llvm::errs());
}
friend bool operator==(const RewritePath &lhs, const RewritePath &rhs) {
return lhs.getBase() == rhs.getBase() && lhs.getPath() == rhs.getPath();
}
};
/// A cache that lazily computes the anchor path for the given equivalence
/// class.
class AnchorPathCache {
GenericSignatureBuilder &builder;
EquivalenceClass &equivClass;
Optional<RewritePath> anchorPath;
public:
AnchorPathCache(GenericSignatureBuilder &builder,
EquivalenceClass &equivClass)
: builder(builder), equivClass(equivClass) { }
const RewritePath &getAnchorPath() {
if (anchorPath) return *anchorPath;
anchorPath = RewritePath::createPath(equivClass.getAnchor(builder, { }));
return *anchorPath;
}
};
/// A node within the prefix tree that is used to match associated type
/// references.
class RewriteTreeNode {
/// The associated type that leads to this node.
///
/// The bit indicates whether there is a rewrite rule for this particular
/// node. If the bit is not set, \c rewrite is invalid.
llvm::PointerIntPair<AssociatedTypeDecl *, 1, bool> assocTypeAndHasRewrite;
/// The sequence of associated types to which a reference to this associated
/// type (from the equivalence class root) can be rewritten. This field is
/// only valid when the bit of \c assocTypeAndHasRewrite is set.
///
/// Consider a requirement "Self.A.B.C == C". This will be encoded as
/// a prefix tree starting at the equivalence class for Self with
/// the following nodes:
///
/// (assocType: A,
/// children: [
/// (assocType: B,
/// children: [
/// (assocType: C, rewrite: [C], children: [])
/// ])
/// ])
RewritePath rewrite;
/// The child nodes, which extend the sequence to be matched.
///
/// The child nodes are sorted by the associated type declaration
/// pointers, so we can perform binary searches quickly.
llvm::TinyPtrVector<RewriteTreeNode *> children;
public:
~RewriteTreeNode();
RewriteTreeNode(AssociatedTypeDecl *assocType)
: assocTypeAndHasRewrite(assocType, false) { }
/// Retrieve the associated type declaration one must match to use this
/// node, which may the
AssociatedTypeDecl *getMatch() const {
return assocTypeAndHasRewrite.getPointer();
}
/// Determine whether this particular node has a rewrite rule.
bool hasRewriteRule() const {
return assocTypeAndHasRewrite.getInt();
}
/// Set a new rewrite rule for this particular node. This can only be
/// performed once.
void setRewriteRule(RewritePath replacementPath) {
assert(!hasRewriteRule());
assocTypeAndHasRewrite.setInt(true);
rewrite = replacementPath;
}
/// Remove the rewrite rule.
void removeRewriteRule() {
assert(hasRewriteRule());
assocTypeAndHasRewrite.setInt(false);
}
/// Retrieve the path to which this node will be rewritten.
const RewritePath &getRewriteRule() const & {
assert(hasRewriteRule());
return rewrite;
}
/// Retrieve the path to which this node will be rewritten.
RewritePath &&getRewriteRule() && {
assert(hasRewriteRule());
return std::move(rewrite);
}
/// Add a new rewrite rule to this tree node.
///
/// \param matchPath The path of associated type declarations that must
/// be matched to produce a rewrite.
///
/// \param replacementPath The sequence of associated type declarations
/// with which a match will be replaced.
///
/// \returns true if a rewrite rule was added, and false if it already
/// existed.
bool addRewriteRule(RelativeRewritePath matchPath,
RewritePath replacementPath);
/// Enumerate all of the paths to which the given matched path can be
/// rewritten.
///
/// \param matchPath The path to match.
///
/// \param callback A callback that will be invoked with (prefix, rewrite)
/// pairs, where \c prefix is the length of the matching prefix of
/// \c matchPath that matched and \c rewrite is the path to which it can
/// be rewritten.
void enumerateRewritePaths(
RelativeRewritePath matchPath,
llvm::function_ref<void(unsigned, RewritePath)> callback) const {
return enumerateRewritePathsImpl(matchPath, callback, /*depth=*/0);
}
private:
void enumerateRewritePathsImpl(
RelativeRewritePath matchPath,
llvm::function_ref<void(unsigned, RewritePath)> callback,
unsigned depth) const;
public:
/// Find the best rewrite rule to match the given path.
///
/// \param path The path to match.
/// \param prefixLength The length of the prefix leading up to \c path.
Optional<std::pair<unsigned, RewritePath>>
bestRewritePath(GenericParamKey base, RelativeRewritePath path,
unsigned prefixLength);
/// Merge the given rewrite tree into \c other.
///
/// \returns true if any rules were created by this merge.
bool mergeInto(RewriteTreeNode *other);
/// An action to perform for the given rule
class RuleAction {
enum Kind {
/// No action; continue traversal.
None,
/// Stop traversal.
Stop,
/// Remove the given rule completely.
Remove,
/// Replace the right-hand side of the rule with the given new path.
Replace,
} kind;
RewritePath path;
RuleAction(Kind kind, RewritePath path = {})
: kind(kind), path(path) { }
friend class RewriteTreeNode;
public:
static RuleAction none() { return RuleAction(None); }
static RuleAction stop() { return RuleAction(Stop); }
static RuleAction remove() { return RuleAction(Remove); }
static RuleAction replace(RewritePath path) {
return RuleAction(Replace, std::move(path));
}
operator Kind() const { return kind; }
};
/// Callback function for enumerating rules in a tree.
using EnumerateCallback =
RuleAction(RelativeRewritePath lhs, const RewritePath &rhs);
/// Enumerate all of the rewrite rules, calling \c fn with the left and
/// right-hand sides of each rule.
///
/// \returns true if the action function returned \c Stop at any point.
bool enumerateRules(llvm::function_ref<EnumerateCallback> fn,
bool temporarilyDisableVisitedRule = false) {
SmallVector<AssociatedTypeDecl *, 4> lhs;
return enumerateRulesRec(fn, temporarilyDisableVisitedRule, lhs);
}
SWIFT_DEBUG_DUMP;
/// Dump the tree.
void dump(llvm::raw_ostream &out, bool lastChild = true) const;
private:
/// Enumerate all of the rewrite rules, calling \c fn with the left and
/// right-hand sides of each rule.
///
/// \returns true if the action function returned \c Stop at any point.
bool enumerateRulesRec(llvm::function_ref<EnumerateCallback> &fn,
bool temporarilyDisableVisitedRule,
llvm::SmallVectorImpl<AssociatedTypeDecl *> &lhs);
};
}
/// A representation of an explicit requirement, used for diagnosing redundant
/// requirements.
///
/// Just like the Requirement data type, this stores the requirement kind and
/// a right hand side (either another type, a protocol, or a layout constraint).
///
/// However, instead of a subject type, we store an explicit requirement source,
/// from which the subject type can be obtained.
class GenericSignatureBuilder::ExplicitRequirement {
llvm::PointerIntPair<const RequirementSource *, 2, RequirementKind> sourceAndKind;
RequirementRHS rhs;
public:
ExplicitRequirement(RequirementKind kind,
const RequirementSource *source,
Type type)
: sourceAndKind(source, kind),
rhs(type ? type->getCanonicalType() : Type()) {}
ExplicitRequirement(RequirementKind kind,
const RequirementSource *source,
ProtocolDecl *proto)
: sourceAndKind(source, kind), rhs(proto) {}
ExplicitRequirement(RequirementKind kind,
const RequirementSource *source,
LayoutConstraint layout)
: sourceAndKind(source, kind), rhs(layout) {}
/// For a Constraint<T> with an explicit requirement source, we recover the
/// subject type from the requirement source and the right hand side from the
/// constraint.
///
/// The requirement kind must be passed in since Constraint<T>'s kind is
/// implicit by virtue of which list it appears under inside its equivalence
/// class, and is not stored inside the constraint.
template<typename T>
static ExplicitRequirement fromExplicitConstraint(RequirementKind kind,
Constraint<T> constraint) {
assert(!constraint.source->isDerivedNonRootRequirement());
return ExplicitRequirement(kind, constraint.source, constraint.value);
}
/// To recover the root explicit requirement from a Constraint<T>, we walk the
/// requirement source up the root, and look at both the root and the next
/// innermost child.
/// Together, these give us the subject type (via the root) and the right hand
/// side of the requirement (from the next innermost child).
///
/// The requirement kind must be passed in since Constraint<T>'s kind is
/// implicit by virtue of which list it appears under inside its equivalence
/// class, and is not stored inside the constraint.
///
/// The constraint's actual value is ignored; that's the right hand
/// side of the derived constraint, not the right hand side of the original
/// explicit requirement.
template<typename T>
static ExplicitRequirement fromDerivedConstraint(RequirementKind kind,
Constraint<T> constraint) {
assert(constraint.source->isDerivedNonRootRequirement());
const RequirementSource *root = constraint.source;
const RequirementSource *child = nullptr;
while (root->parent && root->isDerivedRequirement()) {
child = root;
root = root->parent;
}
assert(root != nullptr);
assert(child != nullptr);
switch (child->kind) {
// If we have a protocol requirement source whose parent is the root, then
// we have an implied constraint coming from a protocol's requirement
// signature:
//
// Explicit: T -> ProtocolRequirement: Self.Iterator (in Sequence)
//
// The root's subject type (T) is the subject of the constraint. The next
// innermost child -- the ProtocolRequirement source -- stores the
// conformed-to protocol declaration.
//
// Therefore the original constraint was 'T : Sequence'.
case RequirementSource::ProtocolRequirement:
case RequirementSource::InferredProtocolRequirement: {
auto *proto = child->getProtocolDecl();
return ExplicitRequirement(RequirementKind::Conformance, root, proto);
}
// If we have a superclass or concrete source whose parent is the root, then
// we have an implied conformance constraint -- either this:
//
// Explicit: T -> Superclass: [MyClass : P]
//
// or this:
//
// Explicit: T -> Concrete: [MyStruct : P]
//
// The original constraint was either 'T : MyClass' or 'T == MyStruct',
// respectively.
case RequirementSource::Superclass:
case RequirementSource::Concrete: {
Type conformingType = child->getStoredType();
if (conformingType) {
// A concrete requirement source for a self-conforming exitential type
// stores the original type, and not the conformance, because there is
// no way to recover the original type from the conformance.
assert(conformingType->isExistentialType());
} else {
auto conformance = child->getProtocolConformance();
if (conformance.isConcrete())
conformingType = conformance.getConcrete()->getType();
else {
// If the conformance was abstract or invalid, we're dealing with
// invalid code. We have no way to recover the superclass type, so
// just stick an ErrorType in there.
auto &ctx = constraint.getSubjectDependentType({ })->getASTContext();
conformingType = ErrorType::get(ctx);
}
}
auto kind = (child->kind == RequirementSource::Superclass
? RequirementKind::Superclass
: RequirementKind::SameType);
return ExplicitRequirement(kind, root, conformingType);
}
// If we have a layout source whose parent is the root, then
// we have an implied layout constraint:
//
// Explicit: T -> Layout: MyClass
//
// The original constraint was the superclass constraint 'T : MyClass'
// (*not* a layout constraint -- this is the layout constraint *implied*
// by a superclass constraint, ensuring that it supercedes an explicit
// 'T : AnyObject' constraint).
case RequirementSource::Layout: {
auto type = child->getStoredType();
return ExplicitRequirement(RequirementKind::Superclass, root, type);
}
default: {
auto &SM = constraint.getSubjectDependentType({ })->getASTContext().SourceMgr;
constraint.source->dump(llvm::errs(), &SM, 0);
llvm::errs() << "\n";
llvm_unreachable("Unknown root kind");
}
}
}
RequirementKind getKind() const {
return sourceAndKind.getInt();
}
const RequirementSource *getSource() const {
return sourceAndKind.getPointer();
}
RequirementRHS getRHS() const {
return rhs;
}
void dump(llvm::raw_ostream &out, SourceManager *SM) const;
static ExplicitRequirement getEmptyKey() {
return ExplicitRequirement(RequirementKind::Conformance, nullptr, nullptr);
}
static ExplicitRequirement getTombstoneKey() {
return ExplicitRequirement(RequirementKind::Superclass, nullptr, Type());
}
friend llvm::hash_code hash_value(const ExplicitRequirement &req) {
using llvm::hash_value;
llvm::hash_code first = hash_value(req.sourceAndKind.getOpaqueValue());
llvm::hash_code second = hash_value(req.rhs.getOpaqueValue());
return llvm::hash_combine(first, second);
}
friend bool operator==(const ExplicitRequirement &lhs,
const ExplicitRequirement &rhs) {
if (lhs.sourceAndKind.getOpaqueValue()
!= rhs.sourceAndKind.getOpaqueValue())
return false;
if (lhs.rhs.getOpaqueValue()
!= rhs.rhs.getOpaqueValue())
return false;
return true;
}
friend bool operator!=(const ExplicitRequirement &lhs,
const ExplicitRequirement &rhs) {
return !(lhs == rhs);
}
};
namespace llvm {
template<> struct DenseMapInfo<swift::GenericSignatureBuilder::ExplicitRequirement> {
static swift::GenericSignatureBuilder::ExplicitRequirement getEmptyKey() {
return swift::GenericSignatureBuilder::ExplicitRequirement::getEmptyKey();
}
static swift::GenericSignatureBuilder::ExplicitRequirement getTombstoneKey() {
return swift::GenericSignatureBuilder::ExplicitRequirement::getTombstoneKey();
}
static unsigned getHashValue(
const swift::GenericSignatureBuilder::ExplicitRequirement &req) {
return hash_value(req);
}
static bool isEqual(const swift::GenericSignatureBuilder::ExplicitRequirement &lhs,
const swift::GenericSignatureBuilder::ExplicitRequirement &rhs) {
return lhs == rhs;
}
};
}
struct GenericSignatureBuilder::Implementation {
/// Allocator.
llvm::BumpPtrAllocator Allocator;
/// The generic parameters that this generic signature builder is working
/// with.
SmallVector<Type, 4> GenericParams;
/// The potential archetypes for the generic parameters in \c GenericParams.
SmallVector<PotentialArchetype *, 4> PotentialArchetypes;
/// The requirement sources used in this generic signature builder.
llvm::FoldingSet<RequirementSource> RequirementSources;
/// The set of requirements that have been delayed for some reason.
SmallVector<DelayedRequirement, 4> DelayedRequirements;
/// The set of equivalence classes.
llvm::iplist<EquivalenceClass> EquivalenceClasses;
/// Equivalence classes that are not currently being used.
std::vector<void *> FreeEquivalenceClasses;
/// The roots of the rewrite tree, keyed on the canonical, dependent
/// types.
DenseMap<CanType, std::unique_ptr<RewriteTreeNode>> RewriteTreeRoots;
/// The generation number for the term-rewriting system, which is
/// increased every time a new rule gets added.
unsigned RewriteGeneration = 0;
/// The generation at which the term-rewriting system was last minimized.
unsigned LastRewriteMinimizedGeneration = 0;
/// The generation number, which is incremented whenever we successfully
/// introduce a new constraint.
unsigned Generation = 0;
/// The generation at which we last processed all of the delayed requirements.
unsigned LastProcessedGeneration = 0;
/// Whether we are currently processing delayed requirements.
bool ProcessingDelayedRequirements = false;
/// Whether we are currently minimizing the term-rewriting system.
bool MinimizingRewriteSystem = false;
/// Whether there were any errors.
bool HadAnyError = false;
/// A mapping of redundant explicit requirements to the best root requirement
/// that implies them.
using RedundantRequirementMap =
llvm::DenseMap<ExplicitRequirement,
llvm::SmallDenseSet<ExplicitRequirement, 2>>;
RedundantRequirementMap RedundantRequirements;
#ifndef NDEBUG
/// Whether we've already computed redundant requiremnts.
bool computedRedundantRequirements = false;
/// Whether we've already finalized the builder.
bool finalized = false;
#endif
/// Tear down an implementation.
~Implementation();
/// Allocate a new equivalence class with the given representative.
EquivalenceClass *allocateEquivalenceClass(
PotentialArchetype *representative);
/// Deallocate the given equivalence class, returning it to the free list.
void deallocateEquivalenceClass(EquivalenceClass *equivClass);
/// Retrieve the rewrite tree root for the given anchor type.
RewriteTreeNode *getRewriteTreeRootIfPresent(CanType anchor);
/// Retrieve the rewrite tree root for the given anchor type,
/// creating it if needed.
RewriteTreeNode *getOrCreateRewriteTreeRoot(CanType anchor);
/// Minimize the rewrite tree by minimizing the right-hand sides and
/// removing redundant rules.
void minimizeRewriteTree(GenericSignatureBuilder &builder);
private:
/// Minimize the right-hand sides of the rewrite tree, simplifying them
/// as far as possible and removing any changes that result in trivial
/// rules.
void minimizeRewriteTreeRhs(GenericSignatureBuilder &builder);
/// Minimize the right-hand sides of the rewrite tree, simplifying them
/// as far as possible and removing any changes that result in trivial
/// rules.
void removeRewriteTreeRedundancies(GenericSignatureBuilder &builder);
};
#pragma mark Memory management
GenericSignatureBuilder::Implementation::~Implementation() {
for (auto pa : PotentialArchetypes)
pa->~PotentialArchetype();
}
EquivalenceClass *
GenericSignatureBuilder::Implementation::allocateEquivalenceClass(
PotentialArchetype *representative) {
void *mem;
if (FreeEquivalenceClasses.empty()) {
// Allocate a new equivalence class.
mem = Allocator.Allocate<EquivalenceClass>();
} else {
// Take an equivalence class from the free list.
mem = FreeEquivalenceClasses.back();
FreeEquivalenceClasses.pop_back();
}
auto equivClass = new (mem) EquivalenceClass(representative);
EquivalenceClasses.push_back(equivClass);
++NumEquivalenceClassesAllocated;
return equivClass;
}
void GenericSignatureBuilder::Implementation::deallocateEquivalenceClass(
EquivalenceClass *equivClass) {
EquivalenceClasses.erase(equivClass);
FreeEquivalenceClasses.push_back(equivClass);
++NumEquivalenceClassesFreed;
}
#pragma mark Requirement sources
#ifndef NDEBUG
bool RequirementSource::isAcceptableStorageKind(Kind kind,
StorageKind storageKind) {
switch (kind) {
case Explicit:
case Inferred:
case RequirementSignatureSelf:
case NestedTypeNameMatch:
case EquivalentType:
case Layout:
switch (storageKind) {
case StorageKind::StoredType:
return true;
case StorageKind::ProtocolConformance:
case StorageKind::AssociatedTypeDecl:
case StorageKind::None:
return false;
}
case Parent:
switch (storageKind) {
case StorageKind::AssociatedTypeDecl:
return true;
case StorageKind::StoredType:
case StorageKind::ProtocolConformance:
case StorageKind::None:
return false;
}
case ProtocolRequirement:
case InferredProtocolRequirement:
switch (storageKind) {
case StorageKind::StoredType:
return true;
case StorageKind::ProtocolConformance:
case StorageKind::AssociatedTypeDecl:
case StorageKind::None:
return false;
}
case Superclass:
case Concrete:
switch (storageKind) {
case StorageKind::StoredType:
case StorageKind::ProtocolConformance:
return true;
case StorageKind::AssociatedTypeDecl:
case StorageKind::None:
return false;
}
}
llvm_unreachable("Unhandled RequirementSourceKind in switch.");
}
#endif
const void *RequirementSource::getOpaqueStorage1() const {
switch (storageKind) {
case StorageKind::None:
return nullptr;
case StorageKind::ProtocolConformance:
return storage.conformance;
case StorageKind::StoredType:
return storage.type;
case StorageKind::AssociatedTypeDecl:
return storage.assocType;
}
llvm_unreachable("Unhandled StorageKind in switch.");
}
const void *RequirementSource::getOpaqueStorage2() const {
if (numTrailingObjects(OverloadToken<ProtocolDecl *>()) == 1)
return getTrailingObjects<ProtocolDecl *>()[0];
if (numTrailingObjects(OverloadToken<WrittenRequirementLoc>()) == 1)
return getTrailingObjects<WrittenRequirementLoc>()[0].getOpaqueValue();
return nullptr;
}
const void *RequirementSource::getOpaqueStorage3() const {
if (numTrailingObjects(OverloadToken<ProtocolDecl *>()) == 1 &&
numTrailingObjects(OverloadToken<WrittenRequirementLoc>()) == 1)
return getTrailingObjects<WrittenRequirementLoc>()[0].getOpaqueValue();
return nullptr;
}
bool RequirementSource::isInferredRequirement() const {
for (auto source = this; source; source = source->parent) {
switch (source->kind) {
case Inferred:
case InferredProtocolRequirement:
case NestedTypeNameMatch:
return true;
case EquivalentType:
return false;
case Concrete:
case Explicit:
case Parent:
case ProtocolRequirement:
case RequirementSignatureSelf:
case Superclass:
case Layout:
break;
}
}
return false;
}
unsigned RequirementSource::classifyDiagKind() const {
if (isInferredRequirement()) return 2;
if (isDerivedRequirement()) return 1;
return 0;
}
bool RequirementSource::isDerivedRequirement() const {
switch (kind) {
case Explicit:
case Inferred:
return false;
case NestedTypeNameMatch:
case Parent:
case Superclass:
case Concrete:
case RequirementSignatureSelf:
case Layout:
case EquivalentType:
return true;
case ProtocolRequirement:
case InferredProtocolRequirement:
// Requirements based on protocol requirements are derived unless they are
// direct children of the requirement-signature source, in which case we
// need to keep them for the requirement signature.
return parent->kind != RequirementSignatureSelf;
}
llvm_unreachable("Unhandled RequirementSourceKind in switch.");
}
bool RequirementSource::isDerivedNonRootRequirement() const {
return (isDerivedRequirement() &&
kind != RequirementSource::RequirementSignatureSelf);
}
bool RequirementSource::shouldDiagnoseRedundancy(bool primary) const {
return !isInferredRequirement() && getLoc().isValid() &&
(!primary || !isDerivedRequirement());
}
bool RequirementSource::isSelfDerivedSource(GenericSignatureBuilder &builder,
Type type,
bool &derivedViaConcrete) const {
return getMinimalConformanceSource(builder, type, /*proto=*/nullptr,
derivedViaConcrete)
!= this;
}
/// Replace 'Self' in the given dependent type (\c depTy) with the given
/// dependent type, producing a type that refers to
/// the nested type. This limited operation makes sure that it does not
/// create any new potential archetypes along the way, so it should only be
/// used in cases where we're reconstructing something that we know exists.
static Type replaceSelfWithType(Type selfType, Type depTy) {
if (auto depMemTy = depTy->getAs<DependentMemberType>()) {
Type baseType = replaceSelfWithType(selfType, depMemTy->getBase());
assert(depMemTy->getAssocType() && "Missing associated type");
return DependentMemberType::get(baseType, depMemTy->getAssocType());
}
assert(depTy->is<GenericTypeParamType>() && "missing Self?");
return selfType;
}
/// Determine whether the given protocol requirement is self-derived when it
/// occurs within the requirement signature of its own protocol.
static bool isSelfDerivedProtocolRequirementInProtocol(
const RequirementSource *source,
ProtocolDecl *selfProto,
GenericSignatureBuilder &builder) {
assert(source->isProtocolRequirement());
// This can only happen if the requirement points comes from the protocol
// itself.
if (source->getProtocolDecl() != selfProto) return false;
// This only applies if the parent is not the anchor for computing the
// requirement signature. Anywhere else, we can use the protocol requirement.
if (source->parent->kind == RequirementSource::RequirementSignatureSelf)
return false;
// If the relative type of the protocol requirement itself is in the
// same equivalence class as what we've proven with this requirement,
// it's a self-derived requirement.
return
builder.resolveEquivalenceClass(source->getAffectedType(),
ArchetypeResolutionKind::WellFormed) ==
builder.resolveEquivalenceClass(source->getStoredType(),
ArchetypeResolutionKind::AlreadyKnown);
}
const RequirementSource *RequirementSource::getMinimalConformanceSource(
GenericSignatureBuilder &builder,
Type currentType,
ProtocolDecl *proto,
bool &derivedViaConcrete) const {
derivedViaConcrete = false;
// If it's not a derived requirement, it's not self-derived.
if (!isDerivedRequirement()) return this;
/// Keep track of all of the requirements we've seen along the way. If
/// we see the same requirement twice, we have found a shorter path.
llvm::DenseMap<std::pair<EquivalenceClass *, ProtocolDecl *>,
const RequirementSource *>
constraintsSeen;
/// Note that we've now seen a new constraint (described on an equivalence
/// class).
auto addConstraint = [&](EquivalenceClass *equivClass, ProtocolDecl *proto,
const RequirementSource *source)
-> const RequirementSource * {
auto &storedSource = constraintsSeen[{equivClass, proto}];
if (storedSource) return storedSource;
storedSource = source;
return nullptr;
};
// Note that we've now seen a new constraint, returning true if we've seen
// it before.
auto addTypeConstraint = [&](Type type, ProtocolDecl *proto,
const RequirementSource *source)
-> const RequirementSource * {
auto equivClass =
builder.resolveEquivalenceClass(type,
ArchetypeResolutionKind::WellFormed);
assert(equivClass && "Not a well-formed type?");
return addConstraint(equivClass, proto, source);
};
bool sawProtocolRequirement = false;
ProtocolDecl *requirementSignatureSelfProto = nullptr;
Type rootType = nullptr;
Optional<std::pair<const RequirementSource *, const RequirementSource *>>
redundantSubpath;
bool isSelfDerived = visitPotentialArchetypesAlongPath(
[&](Type parentType, const RequirementSource *source) {
switch (source->kind) {
case ProtocolRequirement:
case InferredProtocolRequirement: {
// Special handling for top-level requirement signature requirements;
// pretend the root type is the subject type as written in the
// protocol, and not 'Self', so that we can consider this requirement
// self-derived if it depends on one of the conformances that make
// the root type valid.
if (requirementSignatureSelfProto) {
if (source->getProtocolDecl() == requirementSignatureSelfProto &&
source->parent->kind == RequirementSource::RequirementSignatureSelf) {
rootType = source->getAffectedType();
return false;
}
}
// Note that we've seen a protocol requirement.
sawProtocolRequirement = true;
// If the base has been made concrete, note it.
auto parentEquivClass =
builder.resolveEquivalenceClass(parentType,
ArchetypeResolutionKind::WellFormed);
assert(parentEquivClass && "Not a well-formed type?");
if (parentEquivClass->concreteType)
derivedViaConcrete = true;
else if (parentEquivClass->superclass &&
builder.lookupConformance(parentType->getCanonicalType(),
parentEquivClass->superclass,
source->getProtocolDecl()))
derivedViaConcrete = true;
// The parent potential archetype must conform to the protocol in which
// this requirement resides. Add this constraint.
if (auto startOfPath =
addConstraint(parentEquivClass, source->getProtocolDecl(),
source->parent)) {
// We found a redundant subpath; record it and stop the algorithm.
assert(startOfPath != source->parent);
redundantSubpath = { startOfPath, source->parent };
return true;
}
// If this is a self-derived protocol requirement, fail.
if (requirementSignatureSelfProto &&
isSelfDerivedProtocolRequirementInProtocol(
source,
requirementSignatureSelfProto,
builder)) {
redundantSubpath = { source->getRoot(), source->parent };
return true;
}
// No redundancy thus far.
return false;
}
case Parent:
// FIXME: Ad hoc detection of recursive same-type constraints.
return !proto &&
builder.areInSameEquivalenceClass(parentType, currentType);
case Concrete:
case Superclass:
case Layout:
case EquivalentType:
return false;
case RequirementSignatureSelf:
// Note the protocol whose requirement signature the requirement is
// based on.
requirementSignatureSelfProto = source->getProtocolDecl();
LLVM_FALLTHROUGH;
case Explicit:
case Inferred:
case NestedTypeNameMatch:
rootType = parentType;
return false;
}
llvm_unreachable("unhandled kind");
}).isNull();
// If we didn't already find a redundancy, check our end state.
if (!redundantSubpath && proto) {
if (auto startOfPath = addTypeConstraint(currentType, proto, this)) {
redundantSubpath = { startOfPath, this };
assert(startOfPath != this);
isSelfDerived = true;
}
}
// If we saw a constraint twice, it's self-derived.
if (redundantSubpath) {
assert(isSelfDerived && "Not considered self-derived?");
auto shorterSource =
withoutRedundantSubpath(builder,
redundantSubpath->first,
redundantSubpath->second);
return shorterSource
->getMinimalConformanceSource(builder, currentType, proto, derivedViaConcrete);
}
// It's self-derived but we don't have a redundant subpath to eliminate.
if (isSelfDerived)
return nullptr;
// If we haven't seen a protocol requirement, we're done.
if (!sawProtocolRequirement) return this;
// The root might be a nested type, which implies constraints
// for each of the protocols of the associated types referenced (if any).
for (auto depMemTy = rootType->getAs<DependentMemberType>(); depMemTy;
depMemTy = depMemTy->getBase()->getAs<DependentMemberType>()) {
auto assocType = depMemTy->getAssocType();
assert(assocType);
if (addTypeConstraint(depMemTy->getBase(), assocType->getProtocol(),
nullptr))
return nullptr;
}
return this;
}
#define REQUIREMENT_SOURCE_FACTORY_BODY(ProfileArgs, ConstructorArgs, \
NumProtocolDecls, WrittenReq) \
llvm::FoldingSetNodeID nodeID; \
Profile ProfileArgs; \
\
void *insertPos = nullptr; \
if (auto known = \
builder.Impl->RequirementSources.FindNodeOrInsertPos(nodeID, \
insertPos)) \
return known; \
\
unsigned size = \
totalSizeToAlloc<ProtocolDecl *, WrittenRequirementLoc>( \
NumProtocolDecls, \
WrittenReq.isNull()? 0 : 1); \
void *mem = \
builder.Impl->Allocator.Allocate(size, alignof(RequirementSource)); \
auto result = new (mem) RequirementSource ConstructorArgs; \
builder.Impl->RequirementSources.InsertNode(result, insertPos); \
return result
const RequirementSource *RequirementSource::forAbstract(
GenericSignatureBuilder &builder,
Type rootType) {
REQUIREMENT_SOURCE_FACTORY_BODY(
(nodeID, Explicit, nullptr, rootType.getPointer(),
nullptr, nullptr),
(Explicit, rootType, nullptr, WrittenRequirementLoc()),
0, WrittenRequirementLoc());
}
const RequirementSource *RequirementSource::forExplicit(
GenericSignatureBuilder &builder,
Type rootType,
GenericSignatureBuilder::WrittenRequirementLoc writtenLoc) {
REQUIREMENT_SOURCE_FACTORY_BODY(
(nodeID, Explicit, nullptr, rootType.getPointer(),
writtenLoc.getOpaqueValue(), nullptr),
(Explicit, rootType, nullptr, writtenLoc),
0, writtenLoc);
}
const RequirementSource *RequirementSource::forInferred(
GenericSignatureBuilder &builder,
Type rootType,
const TypeRepr *typeRepr) {
WrittenRequirementLoc writtenLoc = typeRepr;
REQUIREMENT_SOURCE_FACTORY_BODY(
(nodeID, Inferred, nullptr, rootType.getPointer(),
writtenLoc.getOpaqueValue(), nullptr),
(Inferred, rootType, nullptr, writtenLoc),
0, writtenLoc);
}
const RequirementSource *RequirementSource::forRequirementSignature(
GenericSignatureBuilder &builder,
Type rootType,
ProtocolDecl *protocol) {
REQUIREMENT_SOURCE_FACTORY_BODY(
(nodeID, RequirementSignatureSelf, nullptr,
rootType.getPointer(), protocol, nullptr),
(RequirementSignatureSelf, rootType, protocol,
WrittenRequirementLoc()),
1, WrittenRequirementLoc());
}
const RequirementSource *RequirementSource::forNestedTypeNameMatch(
GenericSignatureBuilder &builder,
Type rootType) {
REQUIREMENT_SOURCE_FACTORY_BODY(
(nodeID, NestedTypeNameMatch, nullptr,
rootType.getPointer(), nullptr, nullptr),
(NestedTypeNameMatch, rootType, nullptr,
WrittenRequirementLoc()),
0, WrittenRequirementLoc());
}
const RequirementSource *RequirementSource::viaProtocolRequirement(
GenericSignatureBuilder &builder, Type dependentType,
ProtocolDecl *protocol,
bool inferred,
GenericSignatureBuilder::WrittenRequirementLoc writtenLoc) const {
REQUIREMENT_SOURCE_FACTORY_BODY(
(nodeID,
inferred ? InferredProtocolRequirement
: ProtocolRequirement,
this,
dependentType.getPointer(), protocol,
writtenLoc.getOpaqueValue()),
(inferred ? InferredProtocolRequirement
: ProtocolRequirement,
this, dependentType,
protocol, writtenLoc),
1, writtenLoc);
}
const RequirementSource *RequirementSource::viaSuperclass(
GenericSignatureBuilder &builder,
ProtocolConformanceRef conformance) const {
REQUIREMENT_SOURCE_FACTORY_BODY(
(nodeID, Superclass, this, conformance.getOpaqueValue(),
nullptr, nullptr),
(Superclass, this, conformance),
0, WrittenRequirementLoc());
}
const RequirementSource *RequirementSource::viaConcrete(
GenericSignatureBuilder &builder,
ProtocolConformanceRef conformance) const {
REQUIREMENT_SOURCE_FACTORY_BODY(
(nodeID, Concrete, this, conformance.getOpaqueValue(),
nullptr, nullptr),
(Concrete, this, conformance),
0, WrittenRequirementLoc());
}
const RequirementSource *RequirementSource::viaConcrete(
GenericSignatureBuilder &builder,
Type existentialType) const {
assert(existentialType->isExistentialType());
REQUIREMENT_SOURCE_FACTORY_BODY(
(nodeID, Concrete, this, existentialType.getPointer(),
nullptr, nullptr),
(Concrete, this, existentialType),
0, WrittenRequirementLoc());
}
const RequirementSource *RequirementSource::viaParent(
GenericSignatureBuilder &builder,
AssociatedTypeDecl *assocType) const {
REQUIREMENT_SOURCE_FACTORY_BODY(
(nodeID, Parent, this, assocType, nullptr, nullptr),
(Parent, this, assocType),
0, WrittenRequirementLoc());
}
const RequirementSource *RequirementSource::viaLayout(
GenericSignatureBuilder &builder,
Type superclass) const {
REQUIREMENT_SOURCE_FACTORY_BODY(
(nodeID, Layout, this, superclass.getPointer(),
nullptr, nullptr),
(Layout, this, superclass),
0, WrittenRequirementLoc());
}
const RequirementSource *RequirementSource::viaEquivalentType(
GenericSignatureBuilder &builder,
Type newType) const {
REQUIREMENT_SOURCE_FACTORY_BODY(
(nodeID, EquivalentType, this, newType.getPointer(),
nullptr, nullptr),
(EquivalentType, this, newType),
0, WrittenRequirementLoc());
}
#undef REQUIREMENT_SOURCE_FACTORY_BODY
const RequirementSource *RequirementSource::withoutRedundantSubpath(
GenericSignatureBuilder &builder,
const RequirementSource *start,
const RequirementSource *end) const {
// Replace the end with the start; the caller has guaranteed that they
// produce the same thing.
if (this == end) {
#ifndef NDEBUG
// Sanity check: make sure the 'start' precedes the 'end'.
bool foundStart = false;
for (auto source = this; source; source = source->parent) {
if (source == start) {
foundStart = true;
break;
}
}
assert(foundStart && "Start doesn't precede end!");
#endif
return start;
}
switch (kind) {
case Explicit:
case Inferred:
case RequirementSignatureSelf:
case NestedTypeNameMatch:
llvm_unreachable("Subpath end doesn't occur within path");
case ProtocolRequirement:
return parent->withoutRedundantSubpath(builder, start, end)
->viaProtocolRequirement(builder, getStoredType(),
getProtocolDecl(), /*inferred=*/false,
getWrittenRequirementLoc());
case InferredProtocolRequirement:
return parent->withoutRedundantSubpath(builder, start, end)
->viaProtocolRequirement(builder, getStoredType(),
getProtocolDecl(), /*inferred=*/true,
getWrittenRequirementLoc());
case Concrete:
if (auto existentialType = getStoredType()) {
assert(existentialType->isExistentialType());
return parent->withoutRedundantSubpath(builder, start, end)
->viaConcrete(builder, existentialType);
} else {
return parent->withoutRedundantSubpath(builder, start, end)
->viaConcrete(builder, getProtocolConformance());
}
case Layout:
return parent->withoutRedundantSubpath(builder, start, end)
->viaLayout(builder, getStoredType());
case EquivalentType:
return parent->withoutRedundantSubpath(builder, start, end)
->viaEquivalentType(builder, Type(storage.type));
case Parent:
return parent->withoutRedundantSubpath(builder, start, end)
->viaParent(builder, getAssociatedType());
case Superclass:
return parent->withoutRedundantSubpath(builder, start, end)
->viaSuperclass(builder, getProtocolConformance());
}
llvm_unreachable("unhandled kind");
}
const RequirementSource *RequirementSource::getRoot() const {
auto root = this;
while (auto parent = root->parent)
root = parent;
return root;
}
Type RequirementSource::getRootType() const {
/// Find the root.
auto root = getRoot();
// We're at the root, so it's in the inline storage.
assert(root->storageKind == StorageKind::StoredType);
return Type(root->storage.type);
}
Type RequirementSource::getAffectedType() const {
return visitPotentialArchetypesAlongPath(
[](Type, const RequirementSource *) {
return false;
});
}
Type
RequirementSource::visitPotentialArchetypesAlongPath(
llvm::function_ref<bool(Type, const RequirementSource *)> visitor) const {
switch (kind) {
case RequirementSource::Parent: {
Type parentType = parent->visitPotentialArchetypesAlongPath(visitor);
if (!parentType) return nullptr;
if (visitor(parentType, this)) return nullptr;
return replaceSelfWithType(parentType,
getAssociatedType()->getDeclaredInterfaceType());
}
case RequirementSource::NestedTypeNameMatch:
case RequirementSource::Explicit:
case RequirementSource::Inferred:
case RequirementSource::RequirementSignatureSelf: {
Type rootType = getRootType();
if (visitor(rootType, this)) return nullptr;
return rootType;
}
case RequirementSource::Concrete:
case RequirementSource::Superclass:
case RequirementSource::Layout:
return parent->visitPotentialArchetypesAlongPath(visitor);
case RequirementSource::EquivalentType: {
auto parentType = parent->visitPotentialArchetypesAlongPath(visitor);
if (!parentType) return nullptr;
if (visitor(parentType, this)) return nullptr;
return Type(storage.type);
}
case RequirementSource::ProtocolRequirement:
case RequirementSource::InferredProtocolRequirement: {
Type parentType = parent->visitPotentialArchetypesAlongPath(visitor);
if (!parentType) return nullptr;
if (visitor(parentType, this)) return nullptr;
return replaceSelfWithType(parentType, getStoredType());
}
}
llvm_unreachable("unhandled kind");
}
Type RequirementSource::getStoredType() const {
switch (storageKind) {
case StorageKind::None:
case StorageKind::ProtocolConformance:
case StorageKind::AssociatedTypeDecl:
return Type();
case StorageKind::StoredType:
return storage.type;
}
llvm_unreachable("Unhandled StorageKind in switch.");
}
ProtocolDecl *RequirementSource::getProtocolDecl() const {
switch (storageKind) {
case StorageKind::None:
return nullptr;
case StorageKind::StoredType:
if (isProtocolRequirement() || kind == RequirementSignatureSelf)
return getTrailingObjects<ProtocolDecl *>()[0];
return nullptr;
case StorageKind::ProtocolConformance:
return getProtocolConformance().getRequirement();
case StorageKind::AssociatedTypeDecl:
return storage.assocType->getProtocol();
}
llvm_unreachable("Unhandled StorageKind in switch.");
}
SourceLoc RequirementSource::getLoc() const {
// Don't produce locations for protocol requirements unless the parent is
// the protocol self.
// FIXME: We should have a better notion of when to emit diagnostics
// for a particular requirement, rather than turning on/off location info.
// Locations that fall into this category should be advisory, emitted via
// notes rather than as the normal location.
if (isProtocolRequirement() && parent &&
parent->kind != RequirementSignatureSelf)
return parent->getLoc();
if (auto typeRepr = getTypeRepr())
return typeRepr->getStartLoc();
if (auto requirementRepr = getRequirementRepr())
return requirementRepr->getSeparatorLoc();
if (parent)
return parent->getLoc();
if (kind == RequirementSignatureSelf)
return getProtocolDecl()->getLoc();
return SourceLoc();
}
/// Compute the path length of a requirement source, counting only the number
/// of \c ProtocolRequirement elements.
static unsigned sourcePathLength(const RequirementSource *source) {
unsigned count = 0;
for (; source; source = source->parent) {
if (source->isProtocolRequirement())
++count;
}
return count;
}
int RequirementSource::compare(const RequirementSource *other) const {
// Prefer the derived option, if there is one.
bool thisIsDerived = this->isDerivedRequirement();
bool otherIsDerived = other->isDerivedRequirement();
if (thisIsDerived != otherIsDerived)
return thisIsDerived ? -1 : +1;
// Prefer the shorter path.
unsigned thisLength = sourcePathLength(this);
unsigned otherLength = sourcePathLength(other);
if (thisLength != otherLength)
return thisLength < otherLength ? -1 : +1;
// FIXME: Arbitrary hack to allow later requirement sources to stomp on
// earlier ones. We need a proper ordering here.
return +1;
}
void RequirementSource::dump() const {
dump(llvm::errs(), nullptr, 0);
llvm::errs() << "\n";
}
/// Dump the constraint source.
void RequirementSource::dump(llvm::raw_ostream &out, SourceManager *srcMgr,
unsigned indent) const {
// FIXME: Implement for real, so we actually dump the structure.
out.indent(indent);
print(out, srcMgr);
}
void RequirementSource::print() const {
print(llvm::errs(), nullptr);
}
void RequirementSource::print(llvm::raw_ostream &out,
SourceManager *srcMgr) const {
if (parent) {
parent->print(out, srcMgr);
out << " -> ";
} else {
out << getRootType().getString() << ": ";
}
switch (kind) {
case Concrete:
out << "Concrete";
break;
case Explicit:
out << "Explicit";
break;
case Inferred:
out << "Inferred";
break;
case NestedTypeNameMatch:
out << "Nested type match";
break;
case Parent:
out << "Parent";
break;
case ProtocolRequirement:
out << "Protocol requirement";
break;
case InferredProtocolRequirement:
out << "Inferred protocol requirement";
break;
case RequirementSignatureSelf:
out << "Requirement signature self";
break;
case Superclass:
out << "Superclass";
break;
case Layout:
out << "Layout";
break;
case EquivalentType:
out << "Equivalent type";
break;
}
// Local function to dump a source location, if we can.
auto dumpSourceLoc = [&](SourceLoc loc) {
if (!srcMgr) return;
if (loc.isInvalid()) return;
unsigned bufferID = srcMgr->findBufferContainingLoc(loc);
auto lineAndCol = srcMgr->getPresumedLineAndColumnForLoc(loc, bufferID);
out << " @ " << lineAndCol.first << ':' << lineAndCol.second;
};
switch (storageKind) {
case StorageKind::None:
break;
case StorageKind::StoredType:
if (auto proto = getProtocolDecl()) {
out << " (via " << storage.type->getString() << " in " << proto->getName()
<< ")";
}
break;
case StorageKind::ProtocolConformance: {
auto conformance = getProtocolConformance();
if (conformance.isConcrete()) {
out << " (" << conformance.getConcrete()->getType()->getString() << ": "
<< conformance.getConcrete()->getProtocol()->getName() << ")";
} else {
out << " (abstract " << conformance.getRequirement()->getName() << ")";
}
break;
}
case StorageKind::AssociatedTypeDecl:
out << " (" << storage.assocType->getProtocol()->getName()
<< "::" << storage.assocType->getName() << ")";
break;
}
if (getTypeRepr() || getRequirementRepr()) {
dumpSourceLoc(getLoc());
}
}
/// Form the dependent type such that the given protocol's \c Self can be
/// replaced by \c baseType to reach \c type.
static Type formProtocolRelativeType(ProtocolDecl *proto,
Type baseType,
Type type) {
// Error case: hand back the erroneous type.
if (type->hasError())
return type;
// Basis case: we've hit the base potential archetype.
if (baseType->isEqual(type))
return proto->getSelfInterfaceType();
// Recursive case: form a dependent member type.
auto depMemTy = type->castTo<DependentMemberType>();
Type newBaseType = formProtocolRelativeType(proto, baseType,
depMemTy->getBase());
auto assocType = depMemTy->getAssocType();
return DependentMemberType::get(newBaseType, assocType);
}
const RequirementSource *FloatingRequirementSource::getSource(
GenericSignatureBuilder &builder,
ResolvedType type) const {
switch (kind) {
case Resolved:
return storage.get<const RequirementSource *>();
case Explicit: {
auto depType = type.getDependentType(builder);
if (auto requirementRepr = storage.dyn_cast<const RequirementRepr *>())
return RequirementSource::forExplicit(builder, depType, requirementRepr);
if (auto typeRepr = storage.dyn_cast<const TypeRepr *>())
return RequirementSource::forExplicit(builder, depType, typeRepr);
return RequirementSource::forAbstract(builder, depType);
}
case Inferred: {
auto depType = type.getDependentType(builder);
return RequirementSource::forInferred(builder, depType,
storage.get<const TypeRepr *>());
}
case AbstractProtocol: {
auto depType = type.getDependentType();
// Derive the dependent type on which this requirement was written. It is
// the path from the requirement source on which this requirement is based
// to the potential archetype on which the requirement is being placed.
auto baseSource = storage.get<const RequirementSource *>();
auto baseSourceType = baseSource->getAffectedType();
auto dependentType =
formProtocolRelativeType(protocolReq.protocol, baseSourceType, depType);
return storage.get<const RequirementSource *>()
->viaProtocolRequirement(builder, dependentType,
protocolReq.protocol, protocolReq.inferred,
protocolReq.written);
}
case NestedTypeNameMatch: {
auto depType = type.getDependentType(builder);
return RequirementSource::forNestedTypeNameMatch(builder, depType);
}
}
llvm_unreachable("Unhandled FloatingPointRequirementSourceKind in switch.");
}
SourceLoc FloatingRequirementSource::getLoc() const {
// For an explicit abstract protocol source, we can get a more accurate source
// location from the written protocol requirement.
if (kind == Kind::AbstractProtocol && isExplicit()) {
auto written = protocolReq.written;
if (auto typeRepr = written.dyn_cast<const TypeRepr *>())
return typeRepr->getLoc();
if (auto requirementRepr = written.dyn_cast<const RequirementRepr *>())
return requirementRepr->getSeparatorLoc();
}
if (auto source = storage.dyn_cast<const RequirementSource *>())
return source->getLoc();
if (auto typeRepr = storage.dyn_cast<const TypeRepr *>())
return typeRepr->getLoc();
if (auto requirementRepr = storage.dyn_cast<const RequirementRepr *>())
return requirementRepr->getSeparatorLoc();
return SourceLoc();
}
bool FloatingRequirementSource::isDerived() const {
switch (kind) {
case Explicit:
case Inferred:
case NestedTypeNameMatch:
return false;
case AbstractProtocol:
switch (storage.get<const RequirementSource *>()->kind) {
case RequirementSource::RequirementSignatureSelf:
return false;
case RequirementSource::Concrete:
case RequirementSource::Explicit:
case RequirementSource::Inferred:
case RequirementSource::NestedTypeNameMatch:
case RequirementSource::Parent:
case RequirementSource::ProtocolRequirement:
case RequirementSource::InferredProtocolRequirement:
case RequirementSource::Superclass:
case RequirementSource::Layout:
case RequirementSource::EquivalentType:
return true;
}
case Resolved:
return storage.get<const RequirementSource *>()->isDerivedRequirement();
}
llvm_unreachable("unhandled kind");
}
bool FloatingRequirementSource::isExplicit() const {
switch (kind) {
case Explicit:
return true;
case Inferred:
case NestedTypeNameMatch:
return false;
case AbstractProtocol:
// Requirements implied by other protocol conformance requirements are
// implicit, except when computing a requirement signature, where
// non-inferred ones are explicit, to allow flagging of redundant
// requirements.
switch (storage.get<const RequirementSource *>()->kind) {
case RequirementSource::RequirementSignatureSelf:
return !protocolReq.inferred;
case RequirementSource::Concrete:
case RequirementSource::Explicit:
case RequirementSource::Inferred:
case RequirementSource::NestedTypeNameMatch:
case RequirementSource::Parent:
case RequirementSource::ProtocolRequirement:
case RequirementSource::InferredProtocolRequirement:
case RequirementSource::Superclass:
case RequirementSource::Layout:
case RequirementSource::EquivalentType:
return false;
}
case Resolved:
switch (storage.get<const RequirementSource *>()->kind) {
case RequirementSource::Explicit:
return true;
case RequirementSource::ProtocolRequirement:
return storage.get<const RequirementSource *>()->parent->kind
== RequirementSource::RequirementSignatureSelf;
case RequirementSource::Inferred:
case RequirementSource::InferredProtocolRequirement:
case RequirementSource::RequirementSignatureSelf:
case RequirementSource::Concrete:
case RequirementSource::NestedTypeNameMatch:
case RequirementSource::Parent:
case RequirementSource::Superclass:
case RequirementSource::Layout:
case RequirementSource::EquivalentType:
return false;
}
}
llvm_unreachable("unhandled kind");
}
FloatingRequirementSource FloatingRequirementSource::asInferred(
const TypeRepr *typeRepr) const {
switch (kind) {
case Explicit:
return forInferred(typeRepr);
case Inferred:
case Resolved:
case NestedTypeNameMatch:
return *this;
case AbstractProtocol:
return viaProtocolRequirement(storage.get<const RequirementSource *>(),
protocolReq.protocol, typeRepr,
/*inferred=*/true);
}
llvm_unreachable("unhandled kind");
}
bool FloatingRequirementSource::isRecursive(
GenericSignatureBuilder &builder) const {
llvm::SmallSet<std::pair<CanType, ProtocolDecl *>, 32> visitedAssocReqs;
for (auto storedSource = storage.dyn_cast<const RequirementSource *>();
storedSource; storedSource = storedSource->parent) {
// FIXME: isRecursive() is completely misnamed
if (storedSource->kind == RequirementSource::EquivalentType)
return true;
if (!storedSource->isProtocolRequirement())
continue;
if (!visitedAssocReqs.insert(
{storedSource->getStoredType()->getCanonicalType(),
storedSource->getProtocolDecl()}).second)
return true;
}
return false;
}
GenericSignatureBuilder::PotentialArchetype::PotentialArchetype(
PotentialArchetype *parent, AssociatedTypeDecl *assocType)
: parent(parent) {
++NumPotentialArchetypes;
assert(parent != nullptr && "Not a nested type?");
assert(assocType->getOverriddenDecls().empty());
depType = CanDependentMemberType::get(parent->getDependentType(), assocType);
}
GenericSignatureBuilder::PotentialArchetype::PotentialArchetype(
GenericTypeParamType *genericParam)
: parent(nullptr) {
++NumPotentialArchetypes;
depType = genericParam->getCanonicalType();
}
GenericSignatureBuilder::PotentialArchetype::~PotentialArchetype() {
for (const auto &nested : NestedTypes) {
for (auto pa : nested.second) {
pa->~PotentialArchetype();
}
}
}
std::string GenericSignatureBuilder::PotentialArchetype::getDebugName() const {
llvm::SmallString<64> result;
auto parent = getParent();
if (!parent) {
return depType.getString();
}
// Nested types.
result += parent->getDebugName();
// When building the name for debugging purposes, include the protocol into
// which the associated type or type alias was resolved.
auto *proto = getResolvedType()->getProtocol();
result.push_back('[');
result.push_back('.');
result.append(proto->getName().str());
result.push_back(']');
result.push_back('.');
result.append(getResolvedType()->getName().str());
return result.str().str();
}
unsigned GenericSignatureBuilder::PotentialArchetype::getNestingDepth() const {
unsigned Depth = 0;
for (auto P = getParent(); P; P = P->getParent())
++Depth;
return Depth;
}
void EquivalenceClass::addMember(PotentialArchetype *pa) {
assert(find(members, pa) == members.end() &&
"Already have this potential archetype!");
members.push_back(pa);
if (members.back()->getNestingDepth() < members.front()->getNestingDepth()) {
MutableArrayRef<PotentialArchetype *> mutMembers = members;
std::swap(mutMembers.front(), mutMembers.back());
}
}
bool EquivalenceClass::recordConformanceConstraint(
GenericSignatureBuilder &builder,
ResolvedType type,
ProtocolDecl *proto,
const RequirementSource *source) {
// If we haven't seen a conformance to this protocol yet, add it.
bool inserted = false;
auto known = conformsTo.find(proto);
if (known == conformsTo.end()) {
known = conformsTo.insert({ proto, { }}).first;
inserted = true;
modified(builder);
++NumConformances;
// If there is a concrete type that resolves this conformance requirement,
// record the conformance.
if (!builder.resolveConcreteConformance(type, proto)) {
// Otherwise, determine whether there is a superclass constraint where the
// superclass conforms to this protocol.
(void)builder.resolveSuperConformance(type, proto);
}
}
// Record this conformance source.
known->second.push_back({type.getUnresolvedType(), proto, source});
++NumConformanceConstraints;
return inserted;
}
Optional<ConcreteConstraint>
EquivalenceClass::findAnyConcreteConstraintAsWritten(Type preferredType) const {
// If we don't have a concrete type, there's no source.
if (!concreteType) return None;
// Go look for a source with source-location information.
Optional<ConcreteConstraint> result;
for (const auto &constraint : concreteTypeConstraints) {
if (constraint.source->getLoc().isValid()) {
result = constraint;
if (!preferredType ||
constraint.getSubjectDependentType({ })->isEqual(preferredType))
return result;
}
}
return result;
}
Optional<ConcreteConstraint>
EquivalenceClass::findAnySuperclassConstraintAsWritten(
Type preferredType) const {
// If we don't have a superclass, there's no source.
if (!superclass) return None;
// Go look for a source with source-location information.
Optional<ConcreteConstraint> result;
for (const auto &constraint : superclassConstraints) {
if (constraint.source->getLoc().isValid() &&
constraint.value->isEqual(superclass)) {
result = constraint;
if (!preferredType ||
constraint.getSubjectDependentType({ })->isEqual(preferredType))
return result;
}
}
return result;
}
bool EquivalenceClass::isConformanceSatisfiedBySuperclass(
ProtocolDecl *proto) const {
auto known = conformsTo.find(proto);
assert(known != conformsTo.end() && "doesn't conform to this protocol");
for (const auto &constraint: known->second) {
if (constraint.source->kind == RequirementSource::Superclass)
return true;
}
return false;
}
/// Compare two associated types.
static int compareAssociatedTypes(AssociatedTypeDecl *assocType1,
AssociatedTypeDecl *assocType2) {
// - by name.
if (int result = assocType1->getName().str().compare(
assocType2->getName().str()))
return result;
// Prefer an associated type with no overrides (i.e., an anchor) to one
// that has overrides.
bool hasOverridden1 = !assocType1->getOverriddenDecls().empty();
bool hasOverridden2 = !assocType2->getOverriddenDecls().empty();
if (hasOverridden1 != hasOverridden2)
return hasOverridden1 ? +1 : -1;
// - by protocol, so t_n_m.`P.T` < t_n_m.`Q.T` (given P < Q)
auto proto1 = assocType1->getProtocol();
auto proto2 = assocType2->getProtocol();
if (int compareProtocols = TypeDecl::compare(proto1, proto2))
return compareProtocols;
// Error case: if we have two associated types with the same name in the
// same protocol, just tie-break based on address.
if (assocType1 != assocType2)
return assocType1 < assocType2 ? -1 : +1;
return 0;
}
static void lookupConcreteNestedType(NominalTypeDecl *decl,
Identifier name,
SmallVectorImpl<TypeDecl *> &concreteDecls) {
SmallVector<ValueDecl *, 2> foundMembers;
decl->getParentModule()->lookupQualified(
decl, DeclNameRef(name),
NL_QualifiedDefault | NL_OnlyTypes | NL_ProtocolMembers,
foundMembers);
for (auto member : foundMembers)
concreteDecls.push_back(cast<TypeDecl>(member));
}
static auto findBestConcreteNestedType(SmallVectorImpl<TypeDecl *> &concreteDecls) {
return std::min_element(concreteDecls.begin(), concreteDecls.end(),
[](TypeDecl *type1, TypeDecl *type2) {
return TypeDecl::compare(type1, type2) < 0;
});
}
TypeDecl *EquivalenceClass::lookupNestedType(
GenericSignatureBuilder &builder,
Identifier name,
SmallVectorImpl<TypeDecl *> *otherConcreteTypes) {
// Populates the result structures from the given cache entry.
auto populateResult = [&](const CachedNestedType &cache) -> TypeDecl * {
if (otherConcreteTypes)
otherConcreteTypes->clear();
// If there aren't any types in the cache, we're done.
if (cache.types.empty()) return nullptr;
// The first type in the cache is always the final result.
// Collect the rest in the concrete-declarations list, if needed.
if (otherConcreteTypes) {
for (auto type : ArrayRef<TypeDecl *>(cache.types).slice(1)) {
otherConcreteTypes->push_back(type);
}
}
return cache.types.front();
};
// If we have a cached value that is up-to-date, use that.
auto cached = nestedTypeNameCache.find(name);
if (cached != nestedTypeNameCache.end() &&
cached->second.numConformancesPresent == conformsTo.size() &&
(!superclass ||
cached->second.superclassPresent == superclass->getCanonicalType()) &&
(!concreteType ||
cached->second.concreteTypePresent == concreteType->getCanonicalType())) {
++NumNestedTypeCacheHits;
return populateResult(cached->second);
}
// Cache miss; go compute the result.
++NumNestedTypeCacheMisses;
// Look for types with the given name in protocols that we know about.
AssociatedTypeDecl *bestAssocType = nullptr;
SmallVector<TypeDecl *, 4> concreteDecls;
for (const auto &conforms : conformsTo) {
ProtocolDecl *proto = conforms.first;
// Look for an associated type and/or concrete type with this name.
for (auto member : proto->lookupDirect(name)) {
// If this is an associated type, record whether it is the best
// associated type we've seen thus far.
if (auto assocType = dyn_cast<AssociatedTypeDecl>(member)) {
// Retrieve the associated type anchor.
assocType = assocType->getAssociatedTypeAnchor();
if (!bestAssocType ||
compareAssociatedTypes(assocType, bestAssocType) < 0)
bestAssocType = assocType;
continue;
}
// If this is another type declaration, record it.
if (auto type = dyn_cast<TypeDecl>(member)) {
concreteDecls.push_back(type);
continue;
}
}
}
// If we haven't found anything yet but have a concrete type or a superclass,
// look for a type in that.
// FIXME: Shouldn't we always look here?
if (!bestAssocType && concreteDecls.empty()) {
Type typeToSearch = concreteType ? concreteType : superclass;
if (typeToSearch)
if (auto *decl = typeToSearch->getAnyNominal())
lookupConcreteNestedType(decl, name, concreteDecls);
}
// Form the new cache entry.
CachedNestedType entry;
entry.numConformancesPresent = conformsTo.size();
entry.superclassPresent =
superclass ? superclass->getCanonicalType() : CanType();
entry.concreteTypePresent =
concreteType ? concreteType->getCanonicalType() : CanType();
if (bestAssocType) {
entry.types.push_back(bestAssocType);
entry.types.insert(entry.types.end(),
concreteDecls.begin(), concreteDecls.end());
assert(bestAssocType->getOverriddenDecls().empty() &&
"Lookup should never keep a non-anchor associated type");
} else if (!concreteDecls.empty()) {
// Find the best concrete type.
auto bestConcreteTypeIter = findBestConcreteNestedType(concreteDecls);
// Put the best concrete type first; the rest will follow.
entry.types.push_back(*bestConcreteTypeIter);
entry.types.insert(entry.types.end(),
concreteDecls.begin(), bestConcreteTypeIter);
entry.types.insert(entry.types.end(),
bestConcreteTypeIter + 1, concreteDecls.end());
}
return populateResult((nestedTypeNameCache[name] = std::move(entry)));
}
static Type getSugaredDependentType(Type type,
TypeArrayView<GenericTypeParamType> params) {
if (params.empty())
return type;
if (auto *gp = type->getAs<GenericTypeParamType>()) {
unsigned index = GenericParamKey(gp).findIndexIn(params);
return Type(params[index]);
}
auto *dmt = type->castTo<DependentMemberType>();
return DependentMemberType::get(getSugaredDependentType(dmt->getBase(), params),
dmt->getAssocType());
}
Type EquivalenceClass::getAnchor(
GenericSignatureBuilder &builder,
TypeArrayView<GenericTypeParamType> genericParams) {
// Substitute into the anchor with the given generic parameters.
auto substAnchor = [&] {
if (genericParams.empty()) return archetypeAnchorCache.anchor;
return getSugaredDependentType(archetypeAnchorCache.anchor, genericParams);
};
// Check whether the cache is valid.
if (archetypeAnchorCache.anchor &&
archetypeAnchorCache.lastGeneration == builder.Impl->Generation) {
++NumArchetypeAnchorCacheHits;
return substAnchor();
}
// Check whether we already have an anchor, in which case we
// can simplify it further.
if (archetypeAnchorCache.anchor) {
// Record the cache miss.
++NumArchetypeAnchorCacheMisses;
// Update the anchor by simplifying it further.
archetypeAnchorCache.anchor =
builder.getCanonicalTypeParameter(archetypeAnchorCache.anchor);
archetypeAnchorCache.lastGeneration = builder.Impl->Generation;
return substAnchor();
}
// Record the cache miss and update the cache.
++NumArchetypeAnchorCacheMisses;
archetypeAnchorCache.anchor =
builder.getCanonicalTypeParameter(
members.front()->getDependentType());
archetypeAnchorCache.lastGeneration = builder.Impl->Generation;
#ifndef NDEBUG
// All members must produce the same anchor.
for (auto member : members) {
auto anchorType =
builder.getCanonicalTypeParameter(
member->getDependentType());
assert(anchorType->isEqual(archetypeAnchorCache.anchor) &&
"Inconsistent anchor computation");
}
#endif
return substAnchor();
}
Type EquivalenceClass::getTypeInContext(GenericSignatureBuilder &builder,
GenericEnvironment *genericEnv) {
auto genericParams = genericEnv->getGenericParams();
// The anchor descr
Type anchor = getAnchor(builder, genericParams);
// If this equivalence class is mapped to a concrete type, produce that
// type.
if (concreteType) {
if (recursiveConcreteType)
return ErrorType::get(anchor);
// Prevent recursive substitution.
this->recursiveConcreteType = true;
SWIFT_DEFER {
this->recursiveConcreteType = false;
};
return genericEnv->mapTypeIntoContext(concreteType,
builder.getLookupConformanceFn());
}
// Local function to check whether we have a generic parameter that has
// already been recorded
auto getAlreadyRecoveredGenericParam = [&]() -> Type {
auto genericParam = anchor->getAs<GenericTypeParamType>();
if (!genericParam) return Type();
auto type = genericEnv->getMappingIfPresent(genericParam);
if (!type) return Type();
// We already have a mapping for this generic parameter in the generic
// environment. Return it.
return *type;
};
AssociatedTypeDecl *assocType = nullptr;
ArchetypeType *parentArchetype = nullptr;
if (auto depMemTy = anchor->getAs<DependentMemberType>()) {
// Resolve the equivalence class of the parent.
auto parentEquivClass =
builder.resolveEquivalenceClass(
depMemTy->getBase(),
ArchetypeResolutionKind::CompleteWellFormed);
if (!parentEquivClass)
return ErrorType::get(anchor);
// Map the parent type into this context.
parentArchetype =
parentEquivClass->getTypeInContext(builder, genericEnv)
->castTo<ArchetypeType>();
// If we already have a nested type with this name, return it.
assocType = depMemTy->getAssocType();
if (auto nested =
parentArchetype->getNestedTypeIfKnown(assocType->getName())) {
return *nested;
}
// We will build the archetype below.
} else if (auto result = getAlreadyRecoveredGenericParam()) {
// Return already-contextualized generic type parameter.
return result;
}
// Substitute into the superclass.
Type superclass = this->recursiveSuperclassType ? Type() : this->superclass;
if (superclass && superclass->hasTypeParameter()) {
// Prevent recursive substitution.
this->recursiveSuperclassType = true;
SWIFT_DEFER {
this->recursiveSuperclassType = false;
};
superclass = genericEnv->mapTypeIntoContext(
superclass,
builder.getLookupConformanceFn());
if (superclass->is<ErrorType>())
superclass = Type();
// We might have recursively recorded the archetype; if so, return early.
// FIXME: This should be detectable before we end up building archetypes.
if (auto result = getAlreadyRecoveredGenericParam())
return result;
}
// Build a new archetype.
// Collect the protocol conformances for the archetype.
SmallVector<ProtocolDecl *, 4> protos;
for (const auto &conforms : conformsTo) {
auto proto = conforms.first;
if (!isConformanceSatisfiedBySuperclass(proto))
protos.push_back(proto);
}
ArchetypeType *archetype;
ASTContext &ctx = builder.getASTContext();
if (parentArchetype) {
// Create a nested archetype.
auto *depMemTy = anchor->castTo<DependentMemberType>();
archetype = NestedArchetypeType::getNew(ctx, parentArchetype, depMemTy,
protos, superclass, layout);
// Register this archetype with its parent.
parentArchetype->registerNestedType(assocType->getName(), archetype);
} else {
// Create a top-level archetype.
auto genericParam = anchor->castTo<GenericTypeParamType>();
archetype = PrimaryArchetypeType::getNew(ctx, genericEnv, genericParam,
protos, superclass, layout);
// Register the archetype with the generic environment.
genericEnv->addMapping(genericParam, archetype);
}
return archetype;
}
void EquivalenceClass::dump(llvm::raw_ostream &out,
GenericSignatureBuilder *builder) const {
out << "Equivalence class represented by "
<< members.front()->getRepresentative()->getDebugName() << ":\n";
out << "Members: ";
interleave(members, [&](PotentialArchetype *pa) {
out << pa->getDebugName();
}, [&]() {
out << ", ";
});
out << "\n";
out << "Conformance constraints:\n";
for (auto entry : conformsTo) {
out << " " << entry.first->getNameStr() << "\n";
for (auto constraint : entry.second) {
constraint.source->dump(out, &builder->getASTContext().SourceMgr, 4);
if (constraint.source->isDerivedRequirement())
out << " [derived]";
out << "\n";
}
}
out << "Same-type constraints:\n";
for (auto constraint : sameTypeConstraints) {
out << " " << constraint.getSubjectDependentType({})
<< " == " << constraint.value << "\n";
constraint.source->dump(out, &builder->getASTContext().SourceMgr, 4);
if (constraint.source->isDerivedRequirement())
out << " [derived]";
out << "\n";
}
if (concreteType)
out << "Concrete type: " << concreteType.getString() << "\n";
if (superclass)
out << "Superclass: " << superclass.getString() << "\n";
if (layout)
out << "Layout: " << layout.getString() << "\n";
if (!delayedRequirements.empty()) {
out << "Delayed requirements:\n";
for (const auto &req : delayedRequirements) {
req.dump(out);
out << "\n";
}
}
out << "\n";
if (builder) {
CanType anchorType =
const_cast<EquivalenceClass *>(this)->getAnchor(*builder, { })
->getCanonicalType();
if (auto rewriteRoot =
builder->Impl->getRewriteTreeRootIfPresent(anchorType)) {
out << "---Rewrite tree---\n";
rewriteRoot->dump(out);
}
}
}
void EquivalenceClass::dump(GenericSignatureBuilder *builder) const {
dump(llvm::errs(), builder);
}
void DelayedRequirement::dump(llvm::raw_ostream &out) const {
// Print LHS.
if (auto lhsPA = lhs.dyn_cast<PotentialArchetype *>())
out << lhsPA->getDebugName();
else
lhs.get<swift::Type>().print(out);
switch (kind) {
case Type:
case Layout:
out << ": ";
break;
case SameType:
out << " == ";
break;
}
// Print RHS.
if (auto rhsPA = rhs.dyn_cast<PotentialArchetype *>())
out << rhsPA->getDebugName();
else if (auto rhsType = rhs.dyn_cast<swift::Type>())
rhsType.print(out);
else
rhs.get<LayoutConstraint>().print(out);
}
void DelayedRequirement::dump() const {
dump(llvm::errs());
llvm::errs() << "\n";
}
ConstraintResult GenericSignatureBuilder::handleUnresolvedRequirement(
RequirementKind kind,
UnresolvedType lhs,
UnresolvedRequirementRHS rhs,
FloatingRequirementSource source,
EquivalenceClass *unresolvedEquivClass,
UnresolvedHandlingKind unresolvedHandling) {
// Record the delayed requirement.
DelayedRequirement::Kind delayedKind;
switch (kind) {
case RequirementKind::Conformance:
case RequirementKind::Superclass:
delayedKind = DelayedRequirement::Type;
break;
case RequirementKind::Layout:
delayedKind = DelayedRequirement::Layout;
break;
case RequirementKind::SameType:
delayedKind = DelayedRequirement::SameType;
break;
}
if (unresolvedEquivClass) {
unresolvedEquivClass->delayedRequirements.push_back(
{delayedKind, lhs, rhs, source});
} else {
Impl->DelayedRequirements.push_back({delayedKind, lhs, rhs, source});
}
switch (unresolvedHandling) {
case UnresolvedHandlingKind::GenerateConstraints:
return ConstraintResult::Resolved;
case UnresolvedHandlingKind::GenerateUnresolved:
return ConstraintResult::Unresolved;
}
llvm_unreachable("unhandled handling");
}
bool GenericSignatureBuilder::addConditionalRequirements(
ProtocolConformanceRef conformance, ModuleDecl *inferForModule,
SourceLoc loc) {
// Abstract conformances don't have associated decl-contexts/modules, but also
// don't have conditional requirements.
if (conformance.isConcrete()) {
if (auto condReqs = conformance.getConditionalRequirementsIfAvailable()) {
auto source = FloatingRequirementSource::forInferred(nullptr);
for (auto requirement : *condReqs) {
addRequirement(requirement, source, inferForModule);
++NumConditionalRequirementsAdded;
}
} else {
if (loc.isValid())
Diags.diagnose(loc, diag::unsupported_recursive_requirements);
Impl->HadAnyError = true;
return true;
}
}
return false;
}
const RequirementSource *
GenericSignatureBuilder::resolveConcreteConformance(ResolvedType type,
ProtocolDecl *proto) {
auto equivClass = type.getEquivalenceClass(*this);
auto concrete = equivClass->concreteType;
if (!concrete) return nullptr;
// Conformance to this protocol is redundant; update the requirement source
// appropriately.
const RequirementSource *concreteSource;
if (auto writtenSource =
equivClass->findAnyConcreteConstraintAsWritten(nullptr))
concreteSource = writtenSource->source;
else
concreteSource = equivClass->concreteTypeConstraints.front().source;
// Lookup the conformance of the concrete type to this protocol.
auto conformance =
lookupConformance(type.getDependentType(), concrete, proto);
if (conformance.isInvalid()) {
if (!concrete->hasError() && concreteSource->getLoc().isValid()) {
Impl->HadAnyError = true;
Diags.diagnose(concreteSource->getLoc(),
diag::requires_generic_param_same_type_does_not_conform,
concrete, proto->getName());
}
Impl->HadAnyError = true;
equivClass->invalidConcreteType = true;
return nullptr;
}
if (concrete->isExistentialType()) {
// If we have an existential type, record the original type, and
// not the conformance.
//
// The conformance must be a self-conformance, and self-conformances
// do not record the original type in the case where a derived
// protocol self-conforms to a base protocol; for example:
//
// @objc protocol Base {}
//
// @objc protocol Derived {}
//
// struct S<T : Base> {}
//
// extension S where T == Derived {}
assert(isa<SelfProtocolConformance>(conformance.getConcrete()));
concreteSource = concreteSource->viaConcrete(*this, concrete);
} else {
concreteSource = concreteSource->viaConcrete(*this, conformance);
equivClass->recordConformanceConstraint(*this, type, proto, concreteSource);
// Only infer conditional requirements from explicit sources.
bool hasExplicitSource = llvm::any_of(
equivClass->concreteTypeConstraints,
[](const ConcreteConstraint &constraint) {
return (!constraint.source->isDerivedRequirement() &&
constraint.source->getLoc().isValid());
});
if (hasExplicitSource) {
if (addConditionalRequirements(conformance, /*inferForModule=*/nullptr,
concreteSource->getLoc()))
return nullptr;
}
}
return concreteSource;
}
const RequirementSource *GenericSignatureBuilder::resolveSuperConformance(
ResolvedType type,
ProtocolDecl *proto) {
// Get the superclass constraint.
auto equivClass = type.getEquivalenceClass(*this);
Type superclass = equivClass->superclass;
if (!superclass) return nullptr;
// Lookup the conformance of the superclass to this protocol.
auto conformance =
lookupConformance(type.getDependentType(), superclass, proto);
if (conformance.isInvalid())
return nullptr;
assert(!conformance.isAbstract());
// Conformance to this protocol is redundant; update the requirement source
// appropriately.
const RequirementSource *superclassSource;
if (auto writtenSource =
equivClass->findAnySuperclassConstraintAsWritten())
superclassSource = writtenSource->source;
else
superclassSource = equivClass->superclassConstraints.front().source;
superclassSource = superclassSource->viaSuperclass(*this, conformance);
equivClass->recordConformanceConstraint(*this, type, proto, superclassSource);
// Only infer conditional requirements from explicit sources.
bool hasExplicitSource = llvm::any_of(
equivClass->superclassConstraints,
[](const ConcreteConstraint &constraint) {
return (!constraint.source->isDerivedRequirement() &&
constraint.source->getLoc().isValid());
});
if (hasExplicitSource) {
if (addConditionalRequirements(conformance, /*inferForModule=*/nullptr,
superclassSource->getLoc()))
return nullptr;
}
return superclassSource;
}
CanType ResolvedType::getDependentType() const {
return storage.get<PotentialArchetype *>()
->getDependentType();
}
Type ResolvedType::getDependentType(GenericSignatureBuilder &builder) const {
return storage.get<PotentialArchetype *>()
->getDependentType(builder.getGenericParams());
}
auto PotentialArchetype::getOrCreateEquivalenceClass(
GenericSignatureBuilder &builder) const
-> EquivalenceClass * {
// The equivalence class is stored on the representative.
auto representative = getRepresentative();
if (representative != this)
return representative->getOrCreateEquivalenceClass(builder);
// If we already have an equivalence class, return it.
if (auto equivClass = getEquivalenceClassIfPresent())
return equivClass;
// Create a new equivalence class.
auto equivClass =
builder.Impl->allocateEquivalenceClass(
const_cast<PotentialArchetype *>(this));
representativeOrEquivClass = equivClass;
return equivClass;
}
auto PotentialArchetype::getRepresentative() const -> PotentialArchetype * {
auto representative =
representativeOrEquivClass.dyn_cast<PotentialArchetype *>();
if (!representative)
return const_cast<PotentialArchetype *>(this);
// Find the representative.
PotentialArchetype *result = representative;
while (auto nextRepresentative =
result->representativeOrEquivClass.dyn_cast<PotentialArchetype *>())
result = nextRepresentative;
// Perform (full) path compression.
const PotentialArchetype *fixUp = this;
while (auto nextRepresentative =
fixUp->representativeOrEquivClass.dyn_cast<PotentialArchetype *>()) {
fixUp->representativeOrEquivClass = nextRepresentative;
fixUp = nextRepresentative;
}
return result;
}
/// Canonical ordering for dependent types.
int swift::compareDependentTypes(Type type1, Type type2) {
// Fast-path check for equality.
if (type1->isEqual(type2)) return 0;
// Ordering is as follows:
// - Generic params
auto gp1 = type1->getAs<GenericTypeParamType>();
auto gp2 = type2->getAs<GenericTypeParamType>();
if (gp1 && gp2)
return GenericParamKey(gp1) < GenericParamKey(gp2) ? -1 : +1;
// A generic parameter is always ordered before a nested type.
if (static_cast<bool>(gp1) != static_cast<bool>(gp2))
return gp1 ? -1 : +1;
// - Dependent members
auto depMemTy1 = type1->castTo<DependentMemberType>();
auto depMemTy2 = type2->castTo<DependentMemberType>();
// - by base, so t_0_n.`P.T` < t_1_m.`P.T`
if (int compareBases =
compareDependentTypes(depMemTy1->getBase(), depMemTy2->getBase()))
return compareBases;
// - by name, so t_n_m.`P.T` < t_n_m.`P.U`
if (int compareNames = depMemTy1->getName().str().compare(
depMemTy2->getName().str()))
return compareNames;
auto *assocType1 = depMemTy1->getAssocType();
auto *assocType2 = depMemTy2->getAssocType();
if (int result = compareAssociatedTypes(assocType1, assocType2))
return result;
return 0;
}
/// Compare two dependent paths to determine which is better.
static int compareDependentPaths(ArrayRef<AssociatedTypeDecl *> path1,
ArrayRef<AssociatedTypeDecl *> path2) {
// Shorter paths win.
if (path1.size() != path2.size())
return path1.size() < path2.size() ? -1 : 1;
// The paths are the same length, so order by comparing the associted
// types.
for (unsigned index : indices(path1)) {
if (int result = compareAssociatedTypes(path1[index], path2[index]))
return result;
}
// Identical paths.
return 0;
}
namespace {
/// Function object used to suppress conflict diagnoses when we know we'll
/// see them again later.
struct SameTypeConflictCheckedLater {
void operator()(Type type1, Type type2) const { }
};
} // end anonymous namespace
// Give a nested type the appropriately resolved concrete type, based off a
// parent PA that has a concrete type.
static void concretizeNestedTypeFromConcreteParent(
GenericSignatureBuilder::PotentialArchetype *parent,
GenericSignatureBuilder::PotentialArchetype *nestedPA,
GenericSignatureBuilder &builder) {
auto parentEquiv = parent->getEquivalenceClassIfPresent();
assert(parentEquiv && "can't have a concrete type without an equiv class");
bool isSuperclassConstrained = false;
auto concreteParent = parentEquiv->concreteType;
if (!concreteParent) {
isSuperclassConstrained = true;
concreteParent = parentEquiv->superclass;
}
assert(concreteParent &&
"attempting to resolve concrete nested type of non-concrete PA");
// These requirements are all implied based on the parent's concrete
// conformance.
auto assocType = nestedPA->getResolvedType();
if (!assocType) return;
auto proto = assocType->getProtocol();
// If we don't already have a conformance of the parent to this protocol,
// add it now; it was elided earlier.
if (parentEquiv->conformsTo.count(proto) == 0) {
auto source = (!isSuperclassConstrained
? parentEquiv->concreteTypeConstraints.front().source
: parentEquiv->superclassConstraints.front().source);
parentEquiv->recordConformanceConstraint(builder, parent, proto, source);
}
assert(parentEquiv->conformsTo.count(proto) > 0 &&
"No conformance requirement");
const RequirementSource *parentConcreteSource = nullptr;
for (const auto &constraint : parentEquiv->conformsTo.find(proto)->second) {
if (!isSuperclassConstrained) {
if (constraint.source->kind == RequirementSource::Concrete) {
parentConcreteSource = constraint.source;
}
} else {
if (constraint.source->kind == RequirementSource::Superclass) {
parentConcreteSource = constraint.source;
}
}
}
// Error condition: parent did not conform to this protocol, so there is no
// way to resolve the nested type via concrete conformance.
if (!parentConcreteSource) return;
auto source = parentConcreteSource->viaParent(builder, assocType);
auto conformance = parentConcreteSource->getProtocolConformance();
Type witnessType;
if (conformance.isConcrete()) {
witnessType =
conformance.getConcrete()->getTypeWitness(assocType);
if (!witnessType)
return; // FIXME: should we delay here?
} else {
// Otherwise we have an abstract conformance to an opaque result type.
assert(conformance.isAbstract());
auto archetype = concreteParent->castTo<ArchetypeType>();
witnessType = archetype->getNestedType(assocType->getName());
}
builder.addSameTypeRequirement(
nestedPA, witnessType, source,
GenericSignatureBuilder::UnresolvedHandlingKind::GenerateConstraints,
SameTypeConflictCheckedLater());
}
PotentialArchetype *PotentialArchetype::getOrCreateNestedType(
GenericSignatureBuilder &builder, AssociatedTypeDecl *assocType,
ArchetypeResolutionKind kind) {
if (!assocType)
return nullptr;
// Always refer to the archetype anchor.
assocType = assocType->getAssociatedTypeAnchor();
Identifier name = assocType->getName();
SWIFT_DEFER {
// If we were asked for a complete, well-formed archetype, make sure we
// process delayed requirements if anything changed.
if (kind == ArchetypeResolutionKind::CompleteWellFormed)
builder.processDelayedRequirements();
};
// Look for a potential archetype with the appropriate associated type.
auto knownNestedTypes = NestedTypes.find(name);
if (knownNestedTypes != NestedTypes.end()) {
for (auto existingPA : knownNestedTypes->second) {
// Do we have an associated-type match?
if (assocType && existingPA->getResolvedType() == assocType) {
return existingPA;
}
}
}
if (kind == ArchetypeResolutionKind::AlreadyKnown)
return nullptr;
// We don't have a result potential archetype, so we need to add one.
// Creating a new potential archetype in an equivalence class is a
// modification.
getOrCreateEquivalenceClass(builder)->modified(builder);
void *mem = builder.Impl->Allocator.Allocate<PotentialArchetype>();
auto *resultPA = new (mem) PotentialArchetype(this, assocType);
NestedTypes[name].push_back(resultPA);
builder.addedNestedType(resultPA);
// If we know something concrete about the parent PA, we need to propagate
// that information to this new archetype.
if (auto equivClass = getEquivalenceClassIfPresent()) {
if (equivClass->concreteType || equivClass->superclass)
concretizeNestedTypeFromConcreteParent(this, resultPA, builder);
}
return resultPA;
}
void ArchetypeType::resolveNestedType(
std::pair<Identifier, Type> &nested) const {
auto genericEnv = getGenericEnvironment();
auto &builder = *genericEnv->getGenericSignatureBuilder();
Type interfaceType = getInterfaceType();
Type memberInterfaceType =
DependentMemberType::get(interfaceType, nested.first);
auto resolved =
builder.maybeResolveEquivalenceClass(
memberInterfaceType,
ArchetypeResolutionKind::CompleteWellFormed,
/*wantExactPotentialArchetype=*/false);
if (!resolved) {
nested.second = ErrorType::get(interfaceType);
return;
}
Type result;
if (auto concrete = resolved.getAsConcreteType()) {
result = concrete;
} else {
auto *equivClass = resolved.getEquivalenceClass(builder);
result = equivClass->getTypeInContext(builder, genericEnv);
}
assert(!nested.second ||
nested.second->isEqual(result) ||
(nested.second->hasError() && result->hasError()));
nested.second = result;
}
Type GenericSignatureBuilder::PotentialArchetype::getDependentType(
TypeArrayView<GenericTypeParamType> genericParams) const {
auto depType = getDependentType();
return getSugaredDependentType(depType, genericParams);
}
void GenericSignatureBuilder::PotentialArchetype::dump() const {
dump(llvm::errs(), nullptr, 0);
}
void GenericSignatureBuilder::PotentialArchetype::dump(llvm::raw_ostream &Out,
SourceManager *SrcMgr,
unsigned Indent) const {
// Print name.
if (Indent == 0 || isGenericParam())
Out << getDebugName();
else
Out.indent(Indent) << getResolvedType()->getName();
auto equivClass = getEquivalenceClassIfPresent();
// Print superclass.
if (equivClass && equivClass->superclass) {
for (const auto &constraint : equivClass->superclassConstraints) {
if (!constraint.isSubjectEqualTo(this)) continue;
Out << " : ";
constraint.value.print(Out);
Out << " ";
if (!constraint.source->isDerivedRequirement())
Out << "*";
Out << "[";
constraint.source->print(Out, SrcMgr);
Out << "]";
}
}
// Print concrete type.
if (equivClass && equivClass->concreteType) {
for (const auto &constraint : equivClass->concreteTypeConstraints) {
if (!constraint.isSubjectEqualTo(this)) continue;
Out << " == ";
constraint.value.print(Out);
Out << " ";
if (!constraint.source->isDerivedRequirement())
Out << "*";
Out << "[";
constraint.source->print(Out, SrcMgr);
Out << "]";
}
}
// Print requirements.
if (equivClass) {
bool First = true;
for (const auto &entry : equivClass->conformsTo) {
for (const auto &constraint : entry.second) {
if (!constraint.isSubjectEqualTo(this)) continue;
if (First) {
First = false;
Out << ": ";
} else {
Out << " & ";
}
Out << constraint.value->getName().str() << " ";
if (!constraint.source->isDerivedRequirement())
Out << "*";
Out << "[";
constraint.source->print(Out, SrcMgr);
Out << "]";
}
}
}
if (getRepresentative() != this) {
Out << " [represented by " << getRepresentative()->getDebugName() << "]";
}
if (getEquivalenceClassMembers().size() > 1) {
Out << " [equivalence class ";
bool isFirst = true;
for (auto equiv : getEquivalenceClassMembers()) {
if (equiv == this) continue;
if (isFirst) isFirst = false;
else Out << ", ";
Out << equiv->getDebugName();
}
Out << "]";
}
Out << "\n";
// Print nested types.
for (const auto &nestedVec : NestedTypes) {
for (auto nested : nestedVec.second) {
nested->dump(Out, SrcMgr, Indent + 2);
}
}
}
#pragma mark Rewrite tree
RewritePath::RewritePath(Optional<GenericParamKey> base,
RelativeRewritePath path,
PathOrder order)
: base(base)
{
switch (order) {
case Forward:
this->path.insert(this->path.begin(), path.begin(), path.end());
break;
case Reverse:
this->path.insert(this->path.begin(), path.rbegin(), path.rend());
break;
}
}
RewritePath RewritePath::createPath(Type type) {
SmallVector<AssociatedTypeDecl *, 4> path;
auto genericParam = createPath(type, path);
return RewritePath(genericParam, path, Reverse);
}
GenericParamKey RewritePath::createPath(
Type type,
SmallVectorImpl<AssociatedTypeDecl *> &path) {
while (auto depMemTy = type->getAs<DependentMemberType>()) {
auto assocType = depMemTy->getAssocType();
assert(assocType && "Unresolved dependent member type");
path.push_back(assocType);
type = depMemTy->getBase();
}
return type->castTo<GenericTypeParamType>();
}
RewritePath RewritePath::commonPath(const RewritePath &other) const {
assert(getBase().hasValue() && other.getBase().hasValue());
if (*getBase() != *other.getBase()) return RewritePath();
// Find the longest common prefix.
RelativeRewritePath path1 = getPath();
RelativeRewritePath path2 = other.getPath();
if (path1.size() > path2.size())
std::swap(path1, path2);
unsigned prefixLength =
std::mismatch(path1.begin(), path1.end(), path2.begin()).first
- path1.begin();
// Form the common path.
return RewritePath(getBase(), path1.slice(0, prefixLength), Forward);
}
/// Form a dependent type with the given generic parameter, then following the
/// path of associated types.
static Type formDependentType(GenericTypeParamType *base,
RelativeRewritePath path) {
return std::accumulate(path.begin(), path.end(), Type(base),
[](Type type, AssociatedTypeDecl *assocType) -> Type {
return DependentMemberType::get(type, assocType);
});
}
/// Form a dependent type with the (canonical) generic parameter for the given
/// parameter key, then following the path of associated types.
static Type formDependentType(ASTContext &ctx, GenericParamKey genericParam,
RelativeRewritePath path) {
return formDependentType(GenericTypeParamType::get(genericParam.Depth,
genericParam.Index,
ctx),
path);
}
CanType RewritePath::formDependentType(
ASTContext &ctx,
AnchorPathCache *anchorPathCache) const {
if (auto base = getBase())
return CanType(::formDependentType(ctx, *base, getPath()));
assert(anchorPathCache && "Need an anchor path cache");
const RewritePath &anchorPath = anchorPathCache->getAnchorPath();
// Add the relative path to the anchor path.
SmallVector<AssociatedTypeDecl *, 4> absolutePath;
absolutePath.append(anchorPath.getPath().begin(),
anchorPath.getPath().end());
absolutePath.append(getPath().begin(), getPath().end());
return CanType(::formDependentType(ctx, *anchorPath.getBase(),
absolutePath));
}
int RewritePath::compare(const RewritePath &other) const {
// Prefer relative to absolute paths.
if (getBase().hasValue() != other.getBase().hasValue()) {
return other.getBase().hasValue() ? -1 : 1;
}
// Order based on the bases.
if (getBase() && *getBase() != *other.getBase())
return (*getBase() < *other.getBase()) ? -1 : 1;
// Order based on the path contents.
return compareDependentPaths(getPath(), other.getPath());
}
void RewritePath::print(llvm::raw_ostream &out) const {
out << "[";
if (getBase()) {
out << "(" << getBase()->Depth << ", " << getBase()->Index << ")";
if (!getPath().empty()) out << " -> ";
}
llvm::interleave(
getPath().begin(), getPath().end(),
[&](AssociatedTypeDecl *assocType) {
out.changeColor(raw_ostream::BLUE);
out << assocType->getProtocol()->getName() << "."
<< assocType->getName();
out.resetColor();
},
[&] { out << " -> "; });
out << "]";
}
RewriteTreeNode::~RewriteTreeNode() {
for (auto child : children)
delete child;
}
namespace {
/// Function object used to order rewrite tree nodes based on the address
/// of the associated type.
class OrderTreeRewriteNode {
bool compare(AssociatedTypeDecl *lhs, AssociatedTypeDecl *rhs) const {
// Make sure null pointers precede everything else.
if (static_cast<bool>(lhs) != static_cast<bool>(rhs))
return static_cast<bool>(rhs);
// Use std::less to provide a defined ordering.
return std::less<AssociatedTypeDecl *>()(lhs, rhs);
}
public:
bool operator()(RewriteTreeNode *lhs, AssociatedTypeDecl *rhs) const {
return compare(lhs->getMatch(), rhs);
}
bool operator()(AssociatedTypeDecl *lhs, RewriteTreeNode *rhs) const {
return compare(lhs, rhs->getMatch());
}
bool operator()(RewriteTreeNode *lhs, RewriteTreeNode *rhs) const {
return compare(lhs->getMatch(), rhs->getMatch());
}
};
}
bool RewriteTreeNode::addRewriteRule(RelativeRewritePath matchPath,
RewritePath replacementPath) {
// If the match path is empty, we're adding the rewrite rule to this node.
if (matchPath.empty()) {
// If we don't already have a rewrite rule, add it.
if (!hasRewriteRule()) {
setRewriteRule(replacementPath);
return true;
}
// If we already have this rewrite rule, we're done.
if (getRewriteRule() == replacementPath) return false;
// Check whether any of the continuation children matches.
auto insertPos = children.begin();
while (insertPos != children.end() && !(*insertPos)->getMatch()) {
if ((*insertPos)->hasRewriteRule() &&
(*insertPos)->getRewriteRule() == replacementPath)
return false;
++insertPos;
}
// We already have a rewrite rule, so add a new child with a
// null associated type match to hold the rewrite rule.
auto newChild = new RewriteTreeNode(nullptr);
newChild->setRewriteRule(replacementPath);
children.insert(insertPos, newChild);
return true;
}
// Find (or create) a child node describing the next step in the match.
auto matchFront = matchPath.front();
auto childPos =
std::lower_bound(children.begin(), children.end(), matchFront,
OrderTreeRewriteNode());
if (childPos == children.end() || (*childPos)->getMatch() != matchFront) {
childPos = children.insert(childPos, new RewriteTreeNode(matchFront));
}
// Add the rewrite rule to the child.
return (*childPos)->addRewriteRule(matchPath.slice(1), replacementPath);
}
void RewriteTreeNode::enumerateRewritePathsImpl(
RelativeRewritePath matchPath,
llvm::function_ref<void(unsigned, RewritePath)> callback,
unsigned depth) const {
// Determine whether we know anything about the next step in the path.
auto childPos =
depth < matchPath.size()
? std::lower_bound(children.begin(), children.end(),
matchPath[depth], OrderTreeRewriteNode())
: children.end();
if (childPos != children.end() &&
(*childPos)->getMatch() == matchPath[depth]) {
// Try to match the rest of the path.
(*childPos)->enumerateRewritePathsImpl(matchPath, callback, depth + 1);
}
// If we have a rewrite rule at this position, invoke it.
if (hasRewriteRule()) {
// Invoke the callback with the first result.
callback(depth, rewrite);
}
// Walk any children with NULL associated types; they might have more matches.
for (auto otherRewrite : children) {
if (otherRewrite->getMatch()) break;
otherRewrite->enumerateRewritePathsImpl(matchPath, callback, depth);
}
}
Optional<std::pair<unsigned, RewritePath>>
RewriteTreeNode::bestRewritePath(GenericParamKey base, RelativeRewritePath path,
unsigned prefixLength) {
Optional<std::pair<unsigned, RewritePath>> best;
unsigned bestAdjustedLength = 0;
enumerateRewritePaths(path,
[&](unsigned length, RewritePath path) {
// Determine how much of the original path will be replaced by the rewrite.
unsigned adjustedLength = length;
bool changesBase = false;
if (auto newBase = path.getBase()) {
adjustedLength += prefixLength;
// If the base is unchanged, make sure we're reducing the length.
changesBase = *newBase != base;
if (!changesBase && adjustedLength <= path.getPath().size())
return;
}
if (adjustedLength == 0 && !changesBase) return;
if (adjustedLength > bestAdjustedLength || !best ||
(adjustedLength == bestAdjustedLength &&
path.compare(best->second) < 0)) {
best = { length, path };
bestAdjustedLength = adjustedLength;
}
});
return best;
}
bool RewriteTreeNode::mergeInto(RewriteTreeNode *other) {
// FIXME: A destructive version of this operation would be more efficient,
// since we generally don't care about \c other after doing this.
bool anyAdded = false;
(void)enumerateRules([other, &anyAdded](RelativeRewritePath lhs,
const RewritePath &rhs) {
if (other->addRewriteRule(lhs, rhs))
anyAdded = true;
return RuleAction::none();
});
return anyAdded;
}
bool RewriteTreeNode::enumerateRulesRec(
llvm::function_ref<EnumerateCallback> &fn,
bool temporarilyDisableVisitedRule,
llvm::SmallVectorImpl<AssociatedTypeDecl *> &lhs) {
if (auto assocType = getMatch())
lhs.push_back(assocType);
SWIFT_DEFER {
if (getMatch())
lhs.pop_back();
};
// If there is a rewrite rule, invoke the callback.
if (hasRewriteRule()) {
// If we're supposed to temporarily disabled the visited rule, do so
// now.
Optional<RewritePath> rewriteRule;
if (temporarilyDisableVisitedRule) {
rewriteRule = std::move(*this).getRewriteRule();
removeRewriteRule();
}
// Make sure that we put the rewrite rule back in place if we moved it
// aside.
SWIFT_DEFER {
if (temporarilyDisableVisitedRule && rewriteRule)
setRewriteRule(*std::move(rewriteRule));
};
switch (auto action =
fn(lhs, rewriteRule ? *rewriteRule : getRewriteRule())) {
case RuleAction::None:
break;
case RuleAction::Stop:
return true;
case RuleAction::Remove:
if (temporarilyDisableVisitedRule)
rewriteRule = None;
else
removeRewriteRule();
break;
case RuleAction::Replace:
if (temporarilyDisableVisitedRule) {
rewriteRule = std::move(action.path);
} else {
removeRewriteRule();
setRewriteRule(action.path);
}
break;
}
}
// Recurse into the child nodes.
for (auto child : children) {
if (child->enumerateRulesRec(fn, temporarilyDisableVisitedRule, lhs))
return true;
}
return false;
}
void RewriteTreeNode::dump() const {
dump(llvm::errs());
}
void RewriteTreeNode::dump(llvm::raw_ostream &out, bool lastChild) const {
std::string prefixStr;
std::function<void(const RewriteTreeNode *, bool lastChild)> print;
print = [&](const RewriteTreeNode *node, bool lastChild) {
out << prefixStr << " `--";
// Print the node name.
out.changeColor(raw_ostream::GREEN);
if (auto assoc = node->getMatch())
out << assoc->getProtocol()->getName() << "." << assoc->getName();
else
out << "(cont'd)";
out.resetColor();
// Print the rewrite, if there is one.
if (node->hasRewriteRule()) {
out << " --> ";
node->rewrite.print(out);
}
out << "\n";
// Print children.
prefixStr += ' ';
prefixStr += (lastChild ? ' ' : '|');
prefixStr += " ";
for (auto child : node->children) {
print(child, child == node->children.back());
}
prefixStr.erase(prefixStr.end() - 4, prefixStr.end());
};
print(this, lastChild);
}
RewriteTreeNode *
GenericSignatureBuilder::Implementation::getRewriteTreeRootIfPresent(
CanType anchor) {
auto known = RewriteTreeRoots.find(anchor);
if (known != RewriteTreeRoots.end()) return known->second.get();
return nullptr;
}
RewriteTreeNode *
GenericSignatureBuilder::Implementation::getOrCreateRewriteTreeRoot(
CanType anchor) {
if (auto *root = getRewriteTreeRootIfPresent(anchor))
return root;
auto &root = RewriteTreeRoots[anchor];
root = std::make_unique<RewriteTreeNode>(nullptr);
return root.get();
}
void GenericSignatureBuilder::Implementation::minimizeRewriteTree(
GenericSignatureBuilder &builder) {
// Only perform minimization if the term-rewriting tree has changed.
if (LastRewriteMinimizedGeneration == RewriteGeneration
|| MinimizingRewriteSystem)
return;
++NumRewriteMinimizations;
llvm::SaveAndRestore<bool> minimizingRewriteSystem(MinimizingRewriteSystem,
true);
SWIFT_DEFER {
LastRewriteMinimizedGeneration = RewriteGeneration;
};
minimizeRewriteTreeRhs(builder);
removeRewriteTreeRedundancies(builder);
}
void GenericSignatureBuilder::Implementation::minimizeRewriteTreeRhs(
GenericSignatureBuilder &builder) {
assert(MinimizingRewriteSystem);
// Minimize the right-hand sides of each rule in the tree.
for (auto &equivClass : EquivalenceClasses) {
CanType anchorType = equivClass.getAnchor(builder, { })->getCanonicalType();
auto root = RewriteTreeRoots.find(anchorType);
if (root == RewriteTreeRoots.end()) continue;
AnchorPathCache anchorPathCache(builder, equivClass);
ASTContext &ctx = builder.getASTContext();
root->second->enumerateRules([&](RelativeRewritePath lhs,
const RewritePath &rhs) {
// Compute the type of the right-hand side.
Type rhsType = rhs.formDependentType(ctx, &anchorPathCache);
if (!rhsType) return RewriteTreeNode::RuleAction::none();
// Compute the canonical type for the right-hand side.
Type canonicalRhsType = builder.getCanonicalTypeParameter(rhsType);
// If the canonicalized result is equivalent to the right-hand side we
// had, there's nothing to do.
if (rhsType->isEqual(canonicalRhsType))
return RewriteTreeNode::RuleAction::none();
// We have a canonical replacement path. Determine its encoding and
// perform the replacement.
++NumRewriteRhsSimplified;
// Determine replacement path, which might be relative to the anchor.
auto canonicalRhsPath = RewritePath::createPath(canonicalRhsType);
auto anchorPath = anchorPathCache.getAnchorPath();
if (auto prefix = anchorPath.commonPath(canonicalRhsPath)) {
unsigned prefixLength = prefix.getPath().size();
RelativeRewritePath replacementRhsPath =
canonicalRhsPath.getPath().slice(prefixLength);
// If the left and right-hand sides are equivalent, just remove the
// rule.
if (lhs == replacementRhsPath) {
++NumRewriteRhsSimplifiedToLhs;
return RewriteTreeNode::RuleAction::remove();
}
RewritePath replacementRhs(None, replacementRhsPath,
RewritePath::Forward);
return RewriteTreeNode::RuleAction::replace(std::move(replacementRhs));
}
return RewriteTreeNode::RuleAction::replace(canonicalRhsPath);
});
}
}
void GenericSignatureBuilder::Implementation::removeRewriteTreeRedundancies(
GenericSignatureBuilder &builder) {
assert(MinimizingRewriteSystem);
// Minimize the right-hand sides of each rule in the tree.
for (auto &equivClass : EquivalenceClasses) {
CanType anchorType = equivClass.getAnchor(builder, { })->getCanonicalType();
auto root = RewriteTreeRoots.find(anchorType);
if (root == RewriteTreeRoots.end()) continue;
AnchorPathCache anchorPathCache(builder, equivClass);
ASTContext &ctx = builder.getASTContext();
root->second->enumerateRules([&](RelativeRewritePath lhs,
const RewritePath &rhs) {
/// Left-hand side type.
Type lhsType = RewritePath(None, lhs, RewritePath::Forward)
.formDependentType(ctx, &anchorPathCache);
if (!lhsType) return RewriteTreeNode::RuleAction::none();
// Simplify the left-hand type.
Type simplifiedLhsType = builder.getCanonicalTypeParameter(lhsType);
// Compute the type of the right-hand side.
Type rhsType = rhs.formDependentType(ctx, &anchorPathCache);
if (!rhsType) return RewriteTreeNode::RuleAction::none();
if (simplifiedLhsType->isEqual(rhsType)) {
++NumRewriteRulesRedundant;
return RewriteTreeNode::RuleAction::remove();
}
return RewriteTreeNode::RuleAction::none();
},
/*temporarilyDisableVisitedRule=*/true);
}
}
bool GenericSignatureBuilder::addSameTypeRewriteRule(CanType type1,
CanType type2) {
// We already effectively have this rewrite rule.
if (type1 == type2) return false;
auto path1 = RewritePath::createPath(type1);
auto path2 = RewritePath::createPath(type2);
// Look for a common prefix. When we have one, form a rewrite rule using
// relative paths.
if (auto prefix = path1.commonPath(path2)) {
// Find the better relative rewrite path.
RelativeRewritePath relPath1
= path1.getPath().slice(prefix.getPath().size());
RelativeRewritePath relPath2
= path2.getPath().slice(prefix.getPath().size());
// Order the paths so that we go to the more-canonical path.
if (compareDependentPaths(relPath1, relPath2) < 0)
std::swap(relPath1, relPath2);
// Find the anchor for the prefix.
CanType commonType = prefix.formDependentType(getASTContext());
CanType commonAnchor =
getCanonicalTypeParameter(commonType)->getCanonicalType();
// Add the rewrite rule.
auto root = Impl->getOrCreateRewriteTreeRoot(commonAnchor);
return root->addRewriteRule(
relPath1,
RewritePath(None, relPath2, RewritePath::Forward));
}
// Otherwise, form a rewrite rule with absolute paths.
// Find the better path and make sure it's in path2.
if (compareDependentTypes(type1, type2) < 0) {
std::swap(path1, path2);
std::swap(type1, type2);
}
// Add the rewrite rule.
Type firstBase =
GenericTypeParamType::get(path1.getBase()->Depth, path1.getBase()->Index,
getASTContext());
CanType baseAnchor =
getCanonicalTypeParameter(firstBase)->getCanonicalType();
auto root = Impl->getOrCreateRewriteTreeRoot(baseAnchor);
return root->addRewriteRule(path1.getPath(), path2);
}
Type GenericSignatureBuilder::getCanonicalTypeParameter(Type type) {
auto initialPath = RewritePath::createPath(type);
auto genericParamType =
GenericTypeParamType::get(initialPath.getBase()->Depth,
initialPath.getBase()->Index,
getASTContext());
unsigned startIndex = 0;
Type currentType = genericParamType;
SmallVector<AssociatedTypeDecl *, 4> path(initialPath.getPath().begin(),
initialPath.getPath().end());
bool simplified = false;
do {
CanType currentAnchor = currentType->getCanonicalType();
if (auto rootNode = Impl->getRewriteTreeRootIfPresent(currentAnchor)) {
// Find the best rewrite rule for the path starting at startIndex.
auto match =
rootNode->bestRewritePath(genericParamType,
llvm::makeArrayRef(path).slice(startIndex),
startIndex);
// If we have a match, replace the matched path with the replacement
// path.
if (match) {
// Determine the range in the path which we'll be replacing.
unsigned replaceStartIndex = match->second.getBase() ? 0 : startIndex;
unsigned replaceEndIndex = startIndex + match->first;
// Overwrite the beginning of the match.
auto replacementPath = match->second.getPath();
assert((replaceEndIndex - replaceStartIndex) >= replacementPath.size());
auto replacementStartPos = path.begin() + replaceStartIndex;
std::copy(replacementPath.begin(), replacementPath.end(),
replacementStartPos);
// Erase the rest.
path.erase(replacementStartPos + replacementPath.size(),
path.begin() + replaceEndIndex);
// If this is an absolute path, use the new base.
if (auto newBase = match->second.getBase()) {
genericParamType =
GenericTypeParamType::get(newBase->Depth, newBase->Index,
getASTContext());
}
// Move back to the beginning; we may have opened up other rewrites.
simplified = true;
startIndex = 0;
currentType = genericParamType;
continue;
}
}
// If we've hit the end of the path, we're done.
if (startIndex >= path.size()) break;
currentType = DependentMemberType::get(currentType, path[startIndex++]);
} while (true);
return formDependentType(genericParamType, path);
}
#pragma mark Equivalence classes
EquivalenceClass::EquivalenceClass(PotentialArchetype *representative)
: recursiveConcreteType(false), invalidConcreteType(false),
recursiveSuperclassType(false)
{
members.push_back(representative);
}
void EquivalenceClass::modified(GenericSignatureBuilder &builder) {
++builder.Impl->Generation;
// Transfer any delayed requirements to the primary queue, because they
// might be resolvable now.
builder.Impl->DelayedRequirements.append(delayedRequirements.begin(),
delayedRequirements.end());
delayedRequirements.clear();
}
GenericSignatureBuilder::GenericSignatureBuilder(
ASTContext &ctx)
: Context(ctx), Diags(Context.Diags), Impl(new Implementation) {
if (auto *Stats = Context.Stats)
++Stats->getFrontendCounters().NumGenericSignatureBuilders;
}
GenericSignatureBuilder::GenericSignatureBuilder(
GenericSignatureBuilder &&other)
: Context(other.Context), Diags(other.Diags), Impl(std::move(other.Impl))
{
other.Impl.reset();
if (Impl) {
// Update the generic parameters to their canonical types.
for (auto &gp : Impl->GenericParams) {
gp = gp->getCanonicalType()->castTo<GenericTypeParamType>();
}
}
}
GenericSignatureBuilder::~GenericSignatureBuilder() = default;
auto
GenericSignatureBuilder::getLookupConformanceFn()
-> LookUpConformanceInBuilder {
return LookUpConformanceInBuilder(this);
}
ProtocolConformanceRef
GenericSignatureBuilder::LookUpConformanceInBuilder::operator()(
CanType dependentType, Type conformingReplacementType,
ProtocolDecl *conformedProtocol) const {
// Lookup conformances for opened existential.
if (conformingReplacementType->isOpenedExistential()) {
return conformedProtocol->getModuleContext()->lookupConformance(
conformingReplacementType, conformedProtocol);
}
return builder->lookupConformance(dependentType, conformingReplacementType,
conformedProtocol);
}
ProtocolConformanceRef
GenericSignatureBuilder::lookupConformance(CanType dependentType,
Type conformingReplacementType,
ProtocolDecl *conformedProtocol) {
if (conformingReplacementType->isTypeParameter())
return ProtocolConformanceRef(conformedProtocol);
// Figure out which module to look into.
// FIXME: When lookupConformance() starts respecting modules, we'll need
// to do some filtering here.
ModuleDecl *searchModule = conformedProtocol->getParentModule();
return searchModule->lookupConformance(conformingReplacementType,
conformedProtocol);
}
/// Resolve any unresolved dependent member types using the given builder.
static Type resolveDependentMemberTypes(
GenericSignatureBuilder &builder,
Type type,
ArchetypeResolutionKind resolutionKind) {
if (!type->hasTypeParameter()) return type;
return type.transformRec([&resolutionKind,
&builder](TypeBase *type) -> Optional<Type> {
if (!type->isTypeParameter())
return None;
auto resolved = builder.maybeResolveEquivalenceClass(
Type(type), resolutionKind, true);
if (!resolved)
return ErrorType::get(Type(type));
if (auto concreteType = resolved.getAsConcreteType())
return concreteType;
// Map the type parameter to an equivalence class.
auto equivClass = resolved.getEquivalenceClass(builder);
if (!equivClass)
return ErrorType::get(Type(type));
// If there is a concrete type in this equivalence class, use that.
if (equivClass->concreteType) {
// .. unless it's recursive.
if (equivClass->recursiveConcreteType)
return ErrorType::get(Type(type));
// Prevent recursive substitution.
equivClass->recursiveConcreteType = true;
SWIFT_DEFER {
equivClass->recursiveConcreteType = false;
};
return resolveDependentMemberTypes(builder, equivClass->concreteType,
resolutionKind);
}
return equivClass->getAnchor(builder, builder.getGenericParams());
});
}
static Type getStructuralType(TypeDecl *typeDecl, bool keepSugar) {
if (auto typealias = dyn_cast<TypeAliasDecl>(typeDecl)) {
if (typealias->getUnderlyingTypeRepr() != nullptr) {
auto type = typealias->getStructuralType();
if (!keepSugar)
if (auto *aliasTy = cast<TypeAliasType>(type.getPointer()))
return aliasTy->getSinglyDesugaredType();
return type;
}
if (!keepSugar)
return typealias->getUnderlyingType();
}
return typeDecl->getDeclaredInterfaceType();
}
static Type substituteConcreteType(Type parentType,
TypeDecl *concreteDecl) {
if (parentType->is<ErrorType>() ||
parentType->is<UnresolvedType>())
return parentType;
auto *dc = concreteDecl->getDeclContext();
// Form an unsubstituted type referring to the given type declaration,
// for use in an inferred same-type requirement.
auto type = getStructuralType(concreteDecl, /*keepSugar=*/true);
auto subMap = parentType->getContextSubstitutionMap(
dc->getParentModule(), dc);
// If the type has unresolved DependentMemberTypes, we can't use
// Type::subst() if a generic parameter is replaced with a concrete
// type. Instead, perform a "shallow" substitution where we replace
// generic parameter types but leave DependentMemberTypes as-is.
// This means we will end up back in maybeResolveEquivalenceClass(),
// where we will perform the name lookup required to resolve any
// DependentMemberTypes with a concrete base.
if (type->findUnresolvedDependentMemberType()) {
return type.transform([&](Type t) {
if (t->is<GenericTypeParamType>()) {
return t.subst(subMap);
}
return t;
});
}
return type.subst(subMap);
}
ResolvedType GenericSignatureBuilder::maybeResolveEquivalenceClass(
Type type,
ArchetypeResolutionKind resolutionKind,
bool wantExactPotentialArchetype) {
// The equivalence class of a generic type is known directly.
if (auto genericParam = type->getAs<GenericTypeParamType>()) {
unsigned index = GenericParamKey(genericParam).findIndexIn(
getGenericParams());
if (index < Impl->GenericParams.size()) {
return ResolvedType(Impl->PotentialArchetypes[index]);
}
return ResolvedType::forUnresolved(nullptr);
}
// The equivalence class of a dependent member type is determined by its
// base equivalence class, if there is one.
if (auto depMemTy = type->getAs<DependentMemberType>()) {
// Find the equivalence class of the base.
auto resolvedBase =
maybeResolveEquivalenceClass(depMemTy->getBase(),
resolutionKind,
wantExactPotentialArchetype);
if (!resolvedBase) return resolvedBase;
// If the base is concrete, so is this member.
if (auto parentType = resolvedBase.getAsConcreteType()) {
TypeDecl *concreteDecl = depMemTy->getAssocType();
if (!concreteDecl) {
// If we have an unresolved dependent member type, perform a
// name lookup.
if (auto *decl = parentType->getAnyNominal()) {
SmallVector<TypeDecl *, 2> concreteDecls;
lookupConcreteNestedType(decl, depMemTy->getName(), concreteDecls);
if (concreteDecls.empty())
return ResolvedType::forUnresolved(nullptr);
auto bestConcreteTypeIter = findBestConcreteNestedType(concreteDecls);
concreteDecl = *bestConcreteTypeIter;
}
}
auto concreteType = substituteConcreteType(parentType, concreteDecl);
return maybeResolveEquivalenceClass(concreteType, resolutionKind,
wantExactPotentialArchetype);
}
// Find the nested type declaration for this.
auto baseEquivClass = resolvedBase.getEquivalenceClass(*this);
// Retrieve the "smallest" type in the equivalence class, by depth, and
// use that to find a nested potential archetype. We used the smallest
// type by depth to limit expansion of the type graph.
PotentialArchetype *basePA;
if (wantExactPotentialArchetype) {
basePA = resolvedBase.getPotentialArchetypeIfKnown();
if (!basePA)
return ResolvedType::forUnresolved(baseEquivClass);
} else {
basePA = baseEquivClass->members.front();
}
if (auto assocType = depMemTy->getAssocType()) {
// Check whether this associated type references a protocol to which
// the base conforms. If not, it's either concrete or unresolved.
auto *proto = assocType->getProtocol();
if (baseEquivClass->conformsTo.find(proto)
== baseEquivClass->conformsTo.end()) {
if (baseEquivClass->concreteType &&
lookupConformance(type->getCanonicalType(),
baseEquivClass->concreteType,
proto)) {
// Fall through
} else if (baseEquivClass->superclass &&
lookupConformance(type->getCanonicalType(),
baseEquivClass->superclass,
proto)) {
// Fall through
} else {
return ResolvedType::forUnresolved(baseEquivClass);
}
// FIXME: Instead of falling through, we ought to return a concrete
// type here, but then we fail to update a nested PotentialArchetype
// if one happens to already exist. It would be cleaner if concrete
// types never had nested PotentialArchetypes.
}
auto nestedPA =
basePA->getOrCreateNestedType(*this, assocType, resolutionKind);
if (!nestedPA)
return ResolvedType::forUnresolved(baseEquivClass);
return ResolvedType(nestedPA);
} else {
auto *concreteDecl =
baseEquivClass->lookupNestedType(*this, depMemTy->getName());
if (!concreteDecl)
return ResolvedType::forUnresolved(baseEquivClass);
Type parentType;
auto *proto = concreteDecl->getDeclContext()->getSelfProtocolDecl();
if (!proto) {
parentType = (baseEquivClass->concreteType
? baseEquivClass->concreteType
: baseEquivClass->superclass);
} else {
if (baseEquivClass->concreteType &&
lookupConformance(type->getCanonicalType(),
baseEquivClass->concreteType,
proto)) {
parentType = baseEquivClass->concreteType;
} else if (baseEquivClass->superclass &&
lookupConformance(type->getCanonicalType(),
baseEquivClass->superclass,
proto)) {
parentType = baseEquivClass->superclass;
} else {
parentType = basePA->getDependentType(getGenericParams());
}
}
auto concreteType = substituteConcreteType(parentType, concreteDecl);
return maybeResolveEquivalenceClass(concreteType, resolutionKind,
wantExactPotentialArchetype);
}
}
// If it's not a type parameter, it won't directly resolve to one.
// FIXME: Generic typealiases contradict the assumption above.
// If there is a type parameter somewhere in this type, resolve it.
if (type->hasTypeParameter()) {
Type resolved = resolveDependentMemberTypes(*this, type, resolutionKind);
if (resolved->hasError() && !type->hasError())
return ResolvedType::forUnresolved(nullptr);
type = resolved;
}
return ResolvedType::forConcrete(type);
}
EquivalenceClass *GenericSignatureBuilder::resolveEquivalenceClass(
Type type,
ArchetypeResolutionKind resolutionKind) {
if (auto resolved =
maybeResolveEquivalenceClass(type, resolutionKind,
/*wantExactPotentialArchetype=*/false))
return resolved.getEquivalenceClass(*this);
return nullptr;
}
auto GenericSignatureBuilder::resolve(UnresolvedType paOrT,
FloatingRequirementSource source)
-> ResolvedType {
if (auto pa = paOrT.dyn_cast<PotentialArchetype *>())
return ResolvedType(pa);
// Determine what kind of resolution we want.
ArchetypeResolutionKind resolutionKind =
ArchetypeResolutionKind::WellFormed;
if (!source.isExplicit() && source.isRecursive(*this))
resolutionKind = ArchetypeResolutionKind::AlreadyKnown;
Type type = paOrT.get<Type>();
return maybeResolveEquivalenceClass(type, resolutionKind,
/*wantExactPotentialArchetype=*/true);
}
bool GenericSignatureBuilder::areInSameEquivalenceClass(Type type1,
Type type2) {
return resolveEquivalenceClass(type1, ArchetypeResolutionKind::WellFormed)
== resolveEquivalenceClass(type2, ArchetypeResolutionKind::WellFormed);
}
Type GenericSignatureBuilder::getCanonicalTypeInContext(Type type,
TypeArrayView<GenericTypeParamType> genericParams) {
// All the contextual canonicality rules apply to type parameters, so if the
// type doesn't involve any type parameters, it's already canonical.
if (!type->hasTypeParameter())
return type;
// Replace non-canonical type parameters.
return type.transformRec([&](TypeBase *component) -> Optional<Type> {
if (!isa<GenericTypeParamType>(component) &&
!isa<DependentMemberType>(component))
return None;
// Find the equivalence class for this dependent type.
auto resolved = maybeResolveEquivalenceClass(
Type(component),
ArchetypeResolutionKind::CompleteWellFormed,
/*wantExactPotentialArchetype=*/false);
if (!resolved) return None;
if (auto concrete = resolved.getAsConcreteType())
return getCanonicalTypeInContext(concrete, genericParams);
auto equivClass = resolved.getEquivalenceClass(*this);
if (!equivClass) return None;
// If there is a concrete type in this equivalence class, use that.
if (auto concrete = equivClass->concreteType) {
// .. unless it's recursive.
if (equivClass->recursiveConcreteType)
return ErrorType::get(Type(type));
// Prevent recursive substitution.
equivClass->recursiveConcreteType = true;
SWIFT_DEFER {
equivClass->recursiveConcreteType = false;
};
return getCanonicalTypeInContext(concrete, genericParams);
}
return equivClass->getAnchor(*this, genericParams);
});
}
TypeArrayView<GenericTypeParamType>
GenericSignatureBuilder::getGenericParams() const {
return TypeArrayView<GenericTypeParamType>(Impl->GenericParams);
}
void GenericSignatureBuilder::addGenericParameter(GenericTypeParamDecl *GenericParam) {
addGenericParameter(
GenericParam->getDeclaredInterfaceType()->castTo<GenericTypeParamType>());
}
bool GenericSignatureBuilder::addGenericParameterRequirements(
GenericTypeParamDecl *GenericParam) {
GenericParamKey Key(GenericParam);
auto PA = Impl->PotentialArchetypes[Key.findIndexIn(getGenericParams())];
// Add the requirements from the declaration.
return isErrorResult(
addInheritedRequirements(GenericParam, PA, nullptr,
GenericParam->getModuleContext()));
}
void GenericSignatureBuilder::addGenericParameter(GenericTypeParamType *GenericParam) {
auto params = getGenericParams();
(void)params;
assert(params.empty() ||
((GenericParam->getDepth() == params.back()->getDepth() &&
GenericParam->getIndex() == params.back()->getIndex() + 1) ||
(GenericParam->getDepth() > params.back()->getDepth() &&
GenericParam->getIndex() == 0)));
// Create a potential archetype for this type parameter.
auto PA = new (Impl->Allocator) PotentialArchetype(GenericParam);
Impl->GenericParams.push_back(GenericParam);
Impl->PotentialArchetypes.push_back(PA);
}
/// Visit all of the types that show up in the list of inherited
/// types.
static ConstraintResult visitInherited(
llvm::PointerUnion<const TypeDecl *, const ExtensionDecl *> decl,
llvm::function_ref<ConstraintResult(Type, const TypeRepr *)> visitType) {
// Local function that (recursively) adds inherited types.
ConstraintResult result = ConstraintResult::Resolved;
std::function<void(Type, const TypeRepr *)> visitInherited;
visitInherited = [&](Type inheritedType, const TypeRepr *typeRepr) {
// Decompose explicitly-written protocol compositions.
if (auto composition = dyn_cast_or_null<CompositionTypeRepr>(typeRepr)) {
if (auto compositionType
= inheritedType->getAs<ProtocolCompositionType>()) {
unsigned index = 0;
for (auto memberType : compositionType->getMembers()) {
visitInherited(memberType, composition->getTypes()[index]);
++index;
}
return;
}
}
auto recursiveResult = visitType(inheritedType, typeRepr);
if (isErrorResult(recursiveResult) && !isErrorResult(result))
result = recursiveResult;
};
// Visit all of the inherited types.
auto typeDecl = decl.dyn_cast<const TypeDecl *>();
auto extDecl = decl.dyn_cast<const ExtensionDecl *>();
ASTContext &ctx = typeDecl ? typeDecl->getASTContext()
: extDecl->getASTContext();
auto &evaluator = ctx.evaluator;
ArrayRef<TypeLoc> inheritedTypes = typeDecl ? typeDecl->getInherited()
: extDecl->getInherited();
for (unsigned index : indices(inheritedTypes)) {
Type inheritedType
= evaluateOrDefault(evaluator,
InheritedTypeRequest{decl, index,
TypeResolutionStage::Structural},
Type());
if (!inheritedType) continue;
const auto &inherited = inheritedTypes[index];
visitInherited(inheritedType, inherited.getTypeRepr());
}
return result;
}
ConstraintResult GenericSignatureBuilder::expandConformanceRequirement(
ResolvedType selfType,
ProtocolDecl *proto,
const RequirementSource *source,
bool onlySameTypeConstraints) {
auto protocolSubMap = SubstitutionMap::getProtocolSubstitutions(
proto, selfType.getDependentType(*this), ProtocolConformanceRef(proto));
// Use the requirement signature to avoid rewalking the entire protocol. This
// cannot compute the requirement signature directly, because that may be
// infinitely recursive: this code is also used to construct it.
if (!proto->isComputingRequirementSignature()) {
auto innerSource =
FloatingRequirementSource::viaProtocolRequirement(source, proto,
/*inferred=*/false);
for (const auto &req : proto->getRequirementSignature()) {
// If we're only looking at same-type constraints, skip everything else.
if (onlySameTypeConstraints && req.getKind() != RequirementKind::SameType)
continue;
auto substReq = req.subst(protocolSubMap);
auto reqResult = substReq
? addRequirement(*substReq, innerSource, nullptr)
: ConstraintResult::Conflicting;
if (isErrorResult(reqResult)) return reqResult;
}
return ConstraintResult::Resolved;
}
if (!onlySameTypeConstraints) {
// Add all of the inherited protocol requirements, recursively.
auto inheritedReqResult =
addInheritedRequirements(proto, selfType.getUnresolvedType(), source,
proto->getModuleContext());
if (isErrorResult(inheritedReqResult))
return inheritedReqResult;
}
// Add any requirements in the where clause on the protocol.
WhereClauseOwner(proto).visitRequirements(TypeResolutionStage::Structural,
[&](const Requirement &req, RequirementRepr *reqRepr) {
// If we're only looking at same-type constraints, skip everything else.
if (onlySameTypeConstraints &&
req.getKind() != RequirementKind::SameType)
return false;
auto innerSource = FloatingRequirementSource::viaProtocolRequirement(
source, proto, reqRepr, /*inferred=*/false);
addRequirement(req, reqRepr, innerSource, &protocolSubMap,
nullptr);
return false;
});
if (proto->isObjC()) {
// @objc implies an inferred AnyObject constraint.
auto innerSource =
FloatingRequirementSource::viaProtocolRequirement(source, proto,
/*inferred=*/true);
addLayoutRequirementDirect(selfType,
LayoutConstraint::getLayoutConstraint(
LayoutConstraintKind::Class,
getASTContext()),
innerSource);
return ConstraintResult::Resolved;
}
// Remaining logic is not relevant in ObjC protocol cases.
// Collect all of the inherited associated types and typealiases in the
// inherited protocols (recursively).
llvm::MapVector<Identifier, TinyPtrVector<TypeDecl *>> inheritedTypeDecls;
{
proto->walkInheritedProtocols(
[&](ProtocolDecl *inheritedProto) -> TypeWalker::Action {
if (inheritedProto == proto) return TypeWalker::Action::Continue;
for (auto req : inheritedProto->getMembers()) {
if (auto typeReq = dyn_cast<TypeDecl>(req)) {
// Ignore generic types
if (auto genReq = dyn_cast<GenericTypeDecl>(req))
if (genReq->getGenericParams())
continue;
inheritedTypeDecls[typeReq->getName()].push_back(typeReq);
}
}
return TypeWalker::Action::Continue;
});
}
// Local function to find the insertion point for the protocol's "where"
// clause, as well as the string to start the insertion ("where" or ",");
auto getProtocolWhereLoc = [&]() -> Located<const char *> {
// Already has a trailing where clause.
if (auto trailing = proto->getTrailingWhereClause())
return { ", ", trailing->getRequirements().back().getSourceRange().End };
// Inheritance clause.
return { " where ", proto->getInherited().back().getSourceRange().End };
};
// Retrieve the set of requirements that a given associated type declaration
// produces, in the form that would be seen in the where clause.
const auto getAssociatedTypeReqs = [&](const AssociatedTypeDecl *assocType,
const char *start) {
std::string result;
{
llvm::raw_string_ostream out(result);
out << start;
interleave(assocType->getInherited(), [&](TypeLoc inheritedType) {
out << assocType->getName() << ": ";
if (auto inheritedTypeRepr = inheritedType.getTypeRepr())
inheritedTypeRepr->print(out);
else
inheritedType.getType().print(out);
}, [&] {
out << ", ";
});
if (const auto whereClause = assocType->getTrailingWhereClause()) {
if (!assocType->getInherited().empty())
out << ", ";
whereClause->print(out, /*printWhereKeyword*/false);
}
}
return result;
};
// Retrieve the requirement that a given typealias introduces when it
// overrides an inherited associated type with the same name, as a string
// suitable for use in a where clause.
auto getConcreteTypeReq = [&](TypeDecl *type, const char *start) {
std::string result;
{
llvm::raw_string_ostream out(result);
out << start;
out << type->getName() << " == ";
if (auto typealias = dyn_cast<TypeAliasDecl>(type)) {
if (auto underlyingTypeRepr = typealias->getUnderlyingTypeRepr())
underlyingTypeRepr->print(out);
else
typealias->getUnderlyingType().print(out);
} else {
type->print(out);
}
}
return result;
};
// An inferred same-type requirement between the two type declarations
// within this protocol or a protocol it inherits.
auto addInferredSameTypeReq = [&](TypeDecl *first, TypeDecl *second) {
Type firstType = getStructuralType(first, /*keepSugar=*/false);
Type secondType = getStructuralType(second, /*keepSugar=*/false);
auto inferredSameTypeSource =
FloatingRequirementSource::viaProtocolRequirement(
source, proto, WrittenRequirementLoc(), /*inferred=*/true);
auto rawReq = Requirement(RequirementKind::SameType, firstType, secondType);
if (auto req = rawReq.subst(protocolSubMap))
addRequirement(*req, inferredSameTypeSource, proto->getParentModule());
};
// Add requirements for each of the associated types.
for (auto assocTypeDecl : proto->getAssociatedTypeMembers()) {
// Add requirements placed directly on this associated type.
Type assocType =
DependentMemberType::get(selfType.getDependentType(*this), assocTypeDecl);
if (!onlySameTypeConstraints) {
auto assocResult =
addInheritedRequirements(assocTypeDecl, assocType, source,
/*inferForModule=*/nullptr);
if (isErrorResult(assocResult))
return assocResult;
}
// Add requirements from this associated type's where clause.
WhereClauseOwner(assocTypeDecl).visitRequirements(
TypeResolutionStage::Structural,
[&](const Requirement &req, RequirementRepr *reqRepr) {
// If we're only looking at same-type constraints, skip everything else.
if (onlySameTypeConstraints &&
req.getKind() != RequirementKind::SameType)
return false;
auto innerSource = FloatingRequirementSource::viaProtocolRequirement(
source, proto, reqRepr, /*inferred=*/false);
addRequirement(req, reqRepr, innerSource, &protocolSubMap,
/*inferForModule=*/nullptr);
return false;
});
// Check whether we inherited any types with the same name.
auto knownInherited =
inheritedTypeDecls.find(assocTypeDecl->getName());
if (knownInherited == inheritedTypeDecls.end()) continue;
bool shouldWarnAboutRedeclaration =
source->kind == RequirementSource::RequirementSignatureSelf &&
!assocTypeDecl->getAttrs().hasAttribute<NonOverrideAttr>() &&
!assocTypeDecl->getAttrs().hasAttribute<OverrideAttr>() &&
!assocTypeDecl->hasDefaultDefinitionType() &&
(!assocTypeDecl->getInherited().empty() ||
assocTypeDecl->getTrailingWhereClause() ||
getASTContext().LangOpts.WarnImplicitOverrides);
for (auto inheritedType : knownInherited->second) {
// If we have inherited associated type...
if (auto inheritedAssocTypeDecl =
dyn_cast<AssociatedTypeDecl>(inheritedType)) {
// Complain about the first redeclaration.
if (shouldWarnAboutRedeclaration) {
auto inheritedFromProto = inheritedAssocTypeDecl->getProtocol();
auto fixItWhere = getProtocolWhereLoc();
Diags.diagnose(assocTypeDecl,
diag::inherited_associated_type_redecl,
assocTypeDecl->getName(),
inheritedFromProto->getDeclaredInterfaceType())
.fixItInsertAfter(
fixItWhere.Loc,
getAssociatedTypeReqs(assocTypeDecl, fixItWhere.Item))
.fixItRemove(assocTypeDecl->getSourceRange());
Diags.diagnose(inheritedAssocTypeDecl, diag::decl_declared_here,
inheritedAssocTypeDecl->getName());
shouldWarnAboutRedeclaration = false;
}
continue;
}
// We inherited a type; this associated type will be identical
// to that typealias.
if (source->kind == RequirementSource::RequirementSignatureSelf) {
auto inheritedOwningDecl =
inheritedType->getDeclContext()->getSelfNominalTypeDecl();
Diags.diagnose(assocTypeDecl,
diag::associated_type_override_typealias,
assocTypeDecl->getName(),
inheritedOwningDecl->getDescriptiveKind(),
inheritedOwningDecl->getDeclaredInterfaceType());
}
addInferredSameTypeReq(assocTypeDecl, inheritedType);
}
inheritedTypeDecls.erase(knownInherited);
continue;
}
// Check all remaining inherited type declarations to determine if
// this protocol has a non-associated-type type with the same name.
inheritedTypeDecls.remove_if(
[&](const std::pair<Identifier, TinyPtrVector<TypeDecl *>> &inherited) {
const auto name = inherited.first;
for (auto found : proto->lookupDirect(name)) {
// We only want concrete type declarations.
auto type = dyn_cast<TypeDecl>(found);
if (!type || isa<AssociatedTypeDecl>(type)) continue;
// Ignore nominal types. They're always invalid declarations.
if (isa<NominalTypeDecl>(type))
continue;
// ... from the same module as the protocol.
if (type->getModuleContext() != proto->getModuleContext()) continue;
// Ignore types defined in constrained extensions; their equivalence
// to the associated type would have to be conditional, which we cannot
// model.
if (auto ext = dyn_cast<ExtensionDecl>(type->getDeclContext())) {
if (ext->isConstrainedExtension()) continue;
}
// We found something.
bool shouldWarnAboutRedeclaration =
source->kind == RequirementSource::RequirementSignatureSelf;
for (auto inheritedType : inherited.second) {
// If we have inherited associated type...
if (auto inheritedAssocTypeDecl =
dyn_cast<AssociatedTypeDecl>(inheritedType)) {
// Infer a same-type requirement between the typealias' underlying
// type and the inherited associated type.
addInferredSameTypeReq(inheritedAssocTypeDecl, type);
// Warn that one should use where clauses for this.
if (shouldWarnAboutRedeclaration) {
auto inheritedFromProto = inheritedAssocTypeDecl->getProtocol();
auto fixItWhere = getProtocolWhereLoc();
Diags.diagnose(type,
diag::typealias_override_associated_type,
name,
inheritedFromProto->getDeclaredInterfaceType())
.fixItInsertAfter(fixItWhere.Loc,
getConcreteTypeReq(type, fixItWhere.Item))
.fixItRemove(type->getSourceRange());
Diags.diagnose(inheritedAssocTypeDecl, diag::decl_declared_here,
inheritedAssocTypeDecl->getName());
shouldWarnAboutRedeclaration = false;
}
continue;
}
// Two typealiases that should be the same.
addInferredSameTypeReq(inheritedType, type);
}
// We can remove this entry.
return true;
}
return false;
});
// Infer same-type requirements among inherited type declarations.
for (auto &entry : inheritedTypeDecls) {
if (entry.second.size() < 2) continue;
auto firstDecl = entry.second.front();
for (auto otherDecl : ArrayRef<TypeDecl *>(entry.second).slice(1)) {
addInferredSameTypeReq(firstDecl, otherDecl);
}
}
return ConstraintResult::Resolved;
}
ConstraintResult GenericSignatureBuilder::addConformanceRequirement(
ResolvedType type,
ProtocolDecl *proto,
FloatingRequirementSource source) {
auto resolvedSource = source.getSource(*this, type);
// Add the conformance requirement, bailing out earlier if we've already
// seen it.
auto equivClass = type.getEquivalenceClass(*this);
if (!equivClass->recordConformanceConstraint(*this, type, proto,
resolvedSource))
return ConstraintResult::Resolved;
return expandConformanceRequirement(type, proto, resolvedSource,
/*onlySameTypeRequirements=*/false);
}
ConstraintResult GenericSignatureBuilder::addLayoutRequirementDirect(
ResolvedType type,
LayoutConstraint layout,
FloatingRequirementSource source) {
auto equivClass = type.getEquivalenceClass(*this);
// Update the layout in the equivalence class, if we didn't have one already.
bool anyChanges = false;
if (!equivClass->layout) {
equivClass->layout = layout;
anyChanges = true;
} else {
// Try to merge layout constraints.
auto mergedLayout = equivClass->layout.merge(layout);
if (mergedLayout->isKnownLayout() && mergedLayout != equivClass->layout) {
equivClass->layout = mergedLayout;
anyChanges = true;
}
}
// Record this layout constraint.
equivClass->layoutConstraints.push_back({type.getUnresolvedType(),
layout, source.getSource(*this, type)});
equivClass->modified(*this);
++NumLayoutConstraints;
if (!anyChanges) ++NumLayoutConstraintsExtra;
return ConstraintResult::Resolved;
}
ConstraintResult GenericSignatureBuilder::addLayoutRequirement(
UnresolvedType subject,
LayoutConstraint layout,
FloatingRequirementSource source,
UnresolvedHandlingKind unresolvedHandling) {
// Resolve the subject.
auto resolvedSubject = resolve(subject, source);
if (!resolvedSubject) {
return handleUnresolvedRequirement(
RequirementKind::Layout, subject,
layout, source,
resolvedSubject.getUnresolvedEquivClass(),
unresolvedHandling);
}
// If this layout constraint applies to a concrete type, we can fully
// resolve it now.
if (auto concreteType = resolvedSubject.getAsConcreteType()) {
// If a layout requirement was explicitly written on a concrete type,
// complain.
if (source.isExplicit() && source.getLoc().isValid()) {
Impl->HadAnyError = true;
Diags.diagnose(source.getLoc(), diag::requires_not_suitable_archetype,
concreteType);
return ConstraintResult::Concrete;
}
// FIXME: Check whether the layout constraint makes sense for this
// concrete type!
return ConstraintResult::Resolved;
}
return addLayoutRequirementDirect(resolvedSubject, layout, source);
}
bool GenericSignatureBuilder::updateSuperclass(
ResolvedType type,
Type superclass,
FloatingRequirementSource source) {
auto equivClass = type.getEquivalenceClass(*this);
// Local function to handle the update of superclass conformances
// when the superclass constraint changes.
auto updateSuperclassConformances = [&] {
for (const auto &conforms : equivClass->conformsTo) {
(void)resolveSuperConformance(type, conforms.first);
}
// Eagerly resolve any existing nested types to their concrete forms (others
// will be "concretized" as they are constructed, in getNestedType).
for (auto equivT : equivClass->members) {
for (auto nested : equivT->getNestedTypes()) {
concretizeNestedTypeFromConcreteParent(equivT, nested.second.front(),
*this);
}
}
};
// If we haven't yet recorded a superclass constraint for this equivalence
// class, do so now.
if (!equivClass->superclass) {
equivClass->superclass = superclass;
updateSuperclassConformances();
// Presence of a superclass constraint implies a _Class layout
// constraint.
auto layoutReqSource =
source.getSource(*this, type)->viaLayout(*this, superclass);
auto layout =
LayoutConstraint::getLayoutConstraint(
superclass->getClassOrBoundGenericClass()->isObjC()
? LayoutConstraintKind::Class
: LayoutConstraintKind::NativeClass,
getASTContext());
addLayoutRequirementDirect(type, layout, layoutReqSource);
return true;
}
// T already has a superclass; make sure it's related.
auto existingSuperclass = equivClass->superclass;
// TODO: In principle, this could be isBindableToSuperclassOf instead of
// isExactSubclassOf. If you had:
//
// class Foo<T>
// class Bar: Foo<Int>
//
// func foo<T, U where U: Foo<T>, U: Bar>(...) { ... }
//
// then the second constraint should be allowed, constraining U to Bar
// and secondarily imposing a T == Int constraint.
if (existingSuperclass->isExactSuperclassOf(superclass)) {
equivClass->superclass = superclass;
// We've strengthened the bound, so update superclass conformances.
updateSuperclassConformances();
return true;
}
return false;
}
ConstraintResult GenericSignatureBuilder::addSuperclassRequirementDirect(
ResolvedType type,
Type superclass,
FloatingRequirementSource source) {
auto resolvedSource = source.getSource(*this, type);
// Record the constraint.
auto equivClass = type.getEquivalenceClass(*this);
equivClass->superclassConstraints.push_back(
ConcreteConstraint{type.getUnresolvedType(), superclass, resolvedSource});
equivClass->modified(*this);
++NumSuperclassConstraints;
// Update the equivalence class with the constraint.
if (!updateSuperclass(type, superclass, resolvedSource))
++NumSuperclassConstraintsExtra;
return ConstraintResult::Resolved;
}
/// Map an unresolved type to a requirement right-hand-side.
static GenericSignatureBuilder::UnresolvedRequirementRHS
toUnresolvedRequirementRHS(GenericSignatureBuilder::UnresolvedType unresolved) {
if (auto pa = unresolved.dyn_cast<PotentialArchetype *>())
return pa;
return unresolved.dyn_cast<Type>();
}
ConstraintResult GenericSignatureBuilder::addTypeRequirement(
UnresolvedType subject, UnresolvedType constraint,
FloatingRequirementSource source, UnresolvedHandlingKind unresolvedHandling,
ModuleDecl *inferForModule) {
// Resolve the constraint.
auto resolvedConstraint = resolve(constraint, source);
if (!resolvedConstraint) {
return handleUnresolvedRequirement(
RequirementKind::Conformance, subject,
toUnresolvedRequirementRHS(constraint), source,
resolvedConstraint.getUnresolvedEquivClass(),
unresolvedHandling);
}
// The right-hand side needs to be concrete.
Type constraintType = resolvedConstraint.getAsConcreteType();
if (!constraintType) {
constraintType = resolvedConstraint.getDependentType(*this);
assert(constraintType && "No type to express resolved constraint?");
}
// Resolve the subject. If we can't, delay the constraint.
auto resolvedSubject = resolve(subject, source);
if (!resolvedSubject) {
auto recordedKind =
constraintType->isExistentialType()
? RequirementKind::Conformance
: RequirementKind::Superclass;
return handleUnresolvedRequirement(
recordedKind, subject, constraintType,
source,
resolvedSubject.getUnresolvedEquivClass(),
unresolvedHandling);
}
// If the resolved subject is concrete, there may be things we can infer (if it
// conditionally conforms to the protocol), and we can probably perform
// diagnostics here.
if (auto subjectType = resolvedSubject.getAsConcreteType()) {
if (constraintType->isExistentialType()) {
auto layout = constraintType->getExistentialLayout();
for (auto *proto : layout.getProtocols()) {
// We have a pure concrete type, and there's no guarantee of dependent
// type that makes sense to use here, but, in practice, all
// getLookupConformanceFns used in here don't use that parameter anyway.
auto dependentType = CanType();
auto conformance =
getLookupConformanceFn()(dependentType, subjectType, proto->getDecl());
// FIXME: diagnose if there's no conformance.
if (conformance) {
// Only infer conditional requirements from explicit sources.
if (!source.isDerived()) {
if (addConditionalRequirements(conformance, inferForModule,
source.getLoc()))
return ConstraintResult::Conflicting;
}
}
}
}
// One cannot explicitly write a constraint on a concrete type.
if (source.isExplicit()) {
if (source.getLoc().isValid() && !subjectType->hasError()) {
Impl->HadAnyError = true;
Diags.diagnose(source.getLoc(), diag::requires_not_suitable_archetype,
subjectType);
}
return ConstraintResult::Concrete;
}
return ConstraintResult::Resolved;
}
// Check whether we have a reasonable constraint type at all.
if (!constraintType->isExistentialType() &&
!constraintType->getClassOrBoundGenericClass()) {
if (source.getLoc().isValid() && !constraintType->hasError()) {
Impl->HadAnyError = true;
auto invalidConstraint = Constraint<Type>(
{subject, constraintType, source.getSource(*this, resolvedSubject)});
invalidIsaConstraints.push_back(invalidConstraint);
}
return ConstraintResult::Conflicting;
}
// Protocol requirements.
if (constraintType->isExistentialType()) {
bool anyErrors = false;
auto layout = constraintType->getExistentialLayout();
if (auto layoutConstraint = layout.getLayoutConstraint()) {
if (isErrorResult(addLayoutRequirementDirect(resolvedSubject,
layoutConstraint,
source)))
anyErrors = true;
}
if (auto superclass = layout.explicitSuperclass) {
if (isErrorResult(addSuperclassRequirementDirect(resolvedSubject,
superclass,
source)))
anyErrors = true;
}
for (auto *proto : layout.getProtocols()) {
auto *protoDecl = proto->getDecl();
if (isErrorResult(addConformanceRequirement(resolvedSubject, protoDecl,
source)))
anyErrors = true;
}
return anyErrors ? ConstraintResult::Conflicting
: ConstraintResult::Resolved;
}
// Superclass constraint.
return addSuperclassRequirementDirect(resolvedSubject, constraintType,
source);
}
void GenericSignatureBuilder::addedNestedType(PotentialArchetype *nestedPA) {
// If there was already another type with this name within the parent
// potential archetype, equate this type with that one.
auto parentPA = nestedPA->getParent();
auto &allNested = parentPA->NestedTypes[nestedPA->getResolvedType()->getName()];
assert(!allNested.empty());
assert(allNested.back() == nestedPA);
if (allNested.size() > 1) {
auto firstPA = allNested.front();
auto inferredSource =
FloatingRequirementSource::forNestedTypeNameMatch(
nestedPA->getResolvedType()->getName());
addSameTypeRequirement(firstPA, nestedPA, inferredSource,
UnresolvedHandlingKind::GenerateConstraints);
return;
}
// If our parent type is not the representative, equate this nested
// potential archetype to the equivalent nested type within the
// representative.
auto parentRepPA = parentPA->getRepresentative();
if (parentPA == parentRepPA) return;
PotentialArchetype *existingPA =
parentRepPA->getOrCreateNestedType(*this,
nestedPA->getResolvedType(),
ArchetypeResolutionKind::WellFormed);
auto sameNamedSource =
FloatingRequirementSource::forNestedTypeNameMatch(
nestedPA->getResolvedType()->getName());
addSameTypeRequirement(existingPA, nestedPA, sameNamedSource,
UnresolvedHandlingKind::GenerateConstraints);
}
ConstraintResult
GenericSignatureBuilder::addSameTypeRequirementBetweenTypeParameters(
ResolvedType type1, ResolvedType type2,
const RequirementSource *source)
{
++NumSameTypeConstraints;
Type depType1 = type1.getDependentType(*this);
Type depType2 = type2.getDependentType(*this);
// Record the same-type constraint, and bail out if it was already known.
auto equivClass = type1.getEquivalenceClassIfPresent();
auto equivClass2 = type2.getEquivalenceClassIfPresent();
if (depType1->isEqual(depType2) ||
((equivClass || equivClass2) && equivClass == equivClass2)) {
// Make sure we have an equivalence class in which we can record the
// same-type constraint.
if (!equivClass) {
if (equivClass2) {
equivClass = equivClass2;
} else {
equivClass = type1.getEquivalenceClass(*this);
}
}
// FIXME: We could determine equivalence based on both sides canonicalizing
// to the same type.
equivClass->sameTypeConstraints.push_back({depType1, depType2, source});
return ConstraintResult::Resolved;
}
// Both sides are type parameters; equate them.
// FIXME: Realizes potential archetypes far too early.
auto OrigT1 = type1.getPotentialArchetypeIfKnown();
auto OrigT2 = type2.getPotentialArchetypeIfKnown();
// Operate on the representatives
auto T1 = OrigT1->getRepresentative();
auto T2 = OrigT2->getRepresentative();
// Decide which potential archetype is to be considered the representative.
// We prefer potential archetypes with lower nesting depths, because it
// prevents us from unnecessarily building deeply nested potential archetypes.
unsigned nestingDepth1 = T1->getNestingDepth();
unsigned nestingDepth2 = T2->getNestingDepth();
if (nestingDepth2 < nestingDepth1) {
std::swap(T1, T2);
std::swap(OrigT1, OrigT2);
std::swap(equivClass, equivClass2);
}
// T1 must have an equivalence class; create one if we don't already have
// one.
if (!equivClass)
equivClass = T1->getOrCreateEquivalenceClass(*this);
// Record this same-type constraint.
// Let's keep type order in the new constraint the same as it's written
// in source, which makes it much easier to diagnose later.
equivClass->sameTypeConstraints.push_back({depType1, depType2, source});
// Determine the anchor types of the two equivalence classes.
CanType anchor1 = equivClass->getAnchor(*this, { })->getCanonicalType();
CanType anchor2 =
(equivClass2 ? equivClass2->getAnchor(*this, { })
: getCanonicalTypeParameter(T2->getDependentType()))
->getCanonicalType();
// Merge the equivalence classes.
equivClass->modified(*this);
auto equivClass1Members = equivClass->members;
auto equivClass2Members = T2->getEquivalenceClassMembers();
for (auto equiv : equivClass2Members)
equivClass->addMember(equiv);
// Grab the old equivalence class, if present. We'll deallocate it at the end.
SWIFT_DEFER {
if (equivClass2)
Impl->deallocateEquivalenceClass(equivClass2);
};
// Consider the second equivalence class to be modified.
// Transfer Same-type requirements and delayed requirements.
if (equivClass2) {
// Mark as modified and transfer deplayed requirements to the primary queue.
equivClass2->modified(*this);
equivClass->sameTypeConstraints.insert(
equivClass->sameTypeConstraints.end(),
equivClass2->sameTypeConstraints.begin(),
equivClass2->sameTypeConstraints.end());
}
// Combine the rewrite rules.
auto *rewriteRoot1 = Impl->getOrCreateRewriteTreeRoot(anchor1);
auto *rewriteRoot2 = Impl->getOrCreateRewriteTreeRoot(anchor2);
assert(rewriteRoot1 && rewriteRoot2 &&
"Couldn't create/retrieve rewrite tree root");
// Merge the second rewrite tree into the first.
if (rewriteRoot2->mergeInto(rewriteRoot1))
++Impl->RewriteGeneration;
Impl->RewriteTreeRoots.erase(anchor2);
// Add a rewrite rule to map the anchor of T2 down to the anchor of T1.
if (addSameTypeRewriteRule(anchor2, anchor1))
++Impl->RewriteGeneration;
// Same-type-to-concrete requirements.
bool t1IsConcrete = !equivClass->concreteType.isNull();
bool t2IsConcrete = equivClass2 && !equivClass2->concreteType.isNull();
if (t2IsConcrete) {
if (t1IsConcrete) {
(void)addSameTypeRequirement(equivClass->concreteType,
equivClass2->concreteType, source,
UnresolvedHandlingKind::GenerateConstraints,
SameTypeConflictCheckedLater());
} else {
equivClass->concreteType = equivClass2->concreteType;
equivClass->invalidConcreteType = equivClass2->invalidConcreteType;
}
equivClass->concreteTypeConstraints.insert(
equivClass->concreteTypeConstraints.end(),
equivClass2->concreteTypeConstraints.begin(),
equivClass2->concreteTypeConstraints.end());
}
// Make T1 the representative of T2, merging the equivalence classes.
T2->representativeOrEquivClass = T1;
// Layout requirements.
if (equivClass2 && equivClass2->layout) {
if (!equivClass->layout) {
equivClass->layout = equivClass2->layout;
equivClass->layoutConstraints = std::move(equivClass2->layoutConstraints);
} else {
const RequirementSource *source2
= equivClass2->layoutConstraints.front().source;
addLayoutRequirementDirect(T1, equivClass2->layout, source2);
equivClass->layoutConstraints.insert(
equivClass->layoutConstraints.end(),
equivClass2->layoutConstraints.begin() + 1,
equivClass2->layoutConstraints.end());
}
}
// Superclass requirements.
if (equivClass2 && equivClass2->superclass) {
const RequirementSource *source2;
if (auto existingSource2 =
equivClass2->findAnySuperclassConstraintAsWritten(
OrigT2->getDependentType()))
source2 = existingSource2->source;
else
source2 = equivClass2->superclassConstraints.front().source;
// Add the superclass constraints from the second equivalence class.
equivClass->superclassConstraints.insert(
equivClass->superclassConstraints.end(),
equivClass2->superclassConstraints.begin(),
equivClass2->superclassConstraints.end());
(void)updateSuperclass(T1, equivClass2->superclass, source2);
}
// Add all of the protocol conformance requirements of T2 to T1.
if (equivClass2) {
for (const auto &entry : equivClass2->conformsTo) {
equivClass->recordConformanceConstraint(*this, T1, entry.first,
entry.second.front().source);
auto &constraints1 = equivClass->conformsTo[entry.first];
// FIXME: Go through recordConformanceConstraint()?
constraints1.insert(constraints1.end(),
entry.second.begin() + 1,
entry.second.end());
}
}
// Recursively merge the associated types of T2 into T1.
auto dependentT1 = T1->getDependentType(getGenericParams());
SmallPtrSet<Identifier, 4> visited;
for (auto equivT2 : equivClass2Members) {
for (auto T2Nested : equivT2->NestedTypes) {
// Only visit each name once.
if (!visited.insert(T2Nested.first).second) continue;
// If T1 is concrete but T2 is not, concretize the nested types of T2.
if (t1IsConcrete && !t2IsConcrete) {
concretizeNestedTypeFromConcreteParent(T1, T2Nested.second.front(),
*this);
continue;
}
// Otherwise, make the nested types equivalent.
AssociatedTypeDecl *assocTypeT2 = nullptr;
for (auto T2 : T2Nested.second) {
assocTypeT2 = T2->getResolvedType();
if (assocTypeT2) break;
}
if (!assocTypeT2) continue;
Type nestedT1 = DependentMemberType::get(dependentT1, assocTypeT2);
if (isErrorResult(
addSameTypeRequirement(
nestedT1, T2Nested.second.front(),
FloatingRequirementSource::forNestedTypeNameMatch(
assocTypeT2->getName()),
UnresolvedHandlingKind::GenerateConstraints)))
return ConstraintResult::Conflicting;
}
}
// If T2 is concrete but T1 was not, concretize the nested types of T1.
visited.clear();
if (t2IsConcrete && !t1IsConcrete) {
for (auto equivT1 : equivClass1Members) {
for (auto T1Nested : equivT1->NestedTypes) {
// Only visit each name once.
if (!visited.insert(T1Nested.first).second) continue;
concretizeNestedTypeFromConcreteParent(T2, T1Nested.second.front(),
*this);
}
}
}
return ConstraintResult::Resolved;
}
ConstraintResult GenericSignatureBuilder::addSameTypeRequirementToConcrete(
ResolvedType type,
Type concrete,
const RequirementSource *source) {
auto equivClass = type.getEquivalenceClass(*this);
// Record the concrete type and its source.
equivClass->concreteTypeConstraints.push_back(
ConcreteConstraint{type.getUnresolvedType(), concrete, source});
equivClass->modified(*this);
++NumConcreteTypeConstraints;
// If we've already been bound to a type, match that type.
if (equivClass->concreteType) {
return addSameTypeRequirement(equivClass->concreteType, concrete, source,
UnresolvedHandlingKind::GenerateConstraints,
SameTypeConflictCheckedLater());
}
// Record the requirement.
equivClass->concreteType = concrete;
// Make sure the concrete type fulfills the conformance requirements of
// this equivalence class.
for (const auto &conforms : equivClass->conformsTo) {
if (!resolveConcreteConformance(type, conforms.first))
return ConstraintResult::Conflicting;
}
// Eagerly resolve any existing nested types to their concrete forms (others
// will be "concretized" as they are constructed, in getNestedType).
for (auto equivT : equivClass->members) {
for (auto nested : equivT->getNestedTypes()) {
concretizeNestedTypeFromConcreteParent(equivT, nested.second.front(),
*this);
}
}
return ConstraintResult::Resolved;
}
ConstraintResult GenericSignatureBuilder::addSameTypeRequirementBetweenConcrete(
Type type1, Type type2, FloatingRequirementSource source,
llvm::function_ref<void(Type, Type)> diagnoseMismatch) {
// Local class to handle matching the two sides of the same-type constraint.
class ReqTypeMatcher : public TypeMatcher<ReqTypeMatcher> {
GenericSignatureBuilder &builder;
FloatingRequirementSource source;
Type outerType1, outerType2;
llvm::function_ref<void(Type, Type)> diagnoseMismatch;
public:
ReqTypeMatcher(GenericSignatureBuilder &builder,
FloatingRequirementSource source,
Type outerType1, Type outerType2,
llvm::function_ref<void(Type, Type)> diagnoseMismatch)
: builder(builder), source(source), outerType1(outerType1),
outerType2(outerType2), diagnoseMismatch(diagnoseMismatch) {}
bool mismatch(TypeBase *firstType, TypeBase *secondType,
Type sugaredFirstType) {
// If the mismatch was in the first layer (i.e. what was fed to
// addSameTypeRequirementBetweenConcrete), then this is a fundamental
// mismatch, and we need to diagnose it. This is what breaks the mutual
// recursion between addSameTypeRequirement and
// addSameTypeRequirementBetweenConcrete.
if (outerType1->isEqual(firstType) && outerType2->isEqual(secondType)) {
diagnoseMismatch(sugaredFirstType, secondType);
return false;
}
auto failed = builder.addSameTypeRequirement(
sugaredFirstType, Type(secondType), source,
UnresolvedHandlingKind::GenerateConstraints, diagnoseMismatch);
return !isErrorResult(failed);
}
} matcher(*this, source, type1, type2, diagnoseMismatch);
if (matcher.match(type1, type2)) {
// Warn if neither side of the requirement contains a type parameter.
if (source.isTopLevel() && source.getLoc().isValid()) {
Diags.diagnose(source.getLoc(),
diag::requires_no_same_type_archetype,
type1, type2);
}
return ConstraintResult::Resolved;
}
return ConstraintResult::Conflicting;
}
ConstraintResult GenericSignatureBuilder::addSameTypeRequirement(
UnresolvedType paOrT1,
UnresolvedType paOrT2,
FloatingRequirementSource source,
UnresolvedHandlingKind unresolvedHandling) {
return addSameTypeRequirement(paOrT1, paOrT2, source, unresolvedHandling,
[&](Type type1, Type type2) {
Impl->HadAnyError = true;
if (source.getLoc().isValid() &&
!type1->hasError() &&
!type2->hasError()) {
Diags.diagnose(source.getLoc(), diag::requires_same_concrete_type,
type1, type2);
}
});
}
ConstraintResult GenericSignatureBuilder::addSameTypeRequirement(
UnresolvedType paOrT1, UnresolvedType paOrT2,
FloatingRequirementSource source,
UnresolvedHandlingKind unresolvedHandling,
llvm::function_ref<void(Type, Type)> diagnoseMismatch) {
auto resolved1 = resolve(paOrT1, source);
if (!resolved1) {
return handleUnresolvedRequirement(RequirementKind::SameType, paOrT1,
toUnresolvedRequirementRHS(paOrT2),
source,
resolved1.getUnresolvedEquivClass(),
unresolvedHandling);
}
auto resolved2 = resolve(paOrT2, source);
if (!resolved2) {
return handleUnresolvedRequirement(RequirementKind::SameType, paOrT1,
toUnresolvedRequirementRHS(paOrT2),
source,
resolved2.getUnresolvedEquivClass(),
unresolvedHandling);
}
return addSameTypeRequirementDirect(resolved1, resolved2, source,
diagnoseMismatch);
}
ConstraintResult GenericSignatureBuilder::addSameTypeRequirementDirect(
ResolvedType type1, ResolvedType type2,
FloatingRequirementSource source,
llvm::function_ref<void(Type, Type)> diagnoseMismatch) {
auto concreteType1 = type1.getAsConcreteType();
auto concreteType2 = type2.getAsConcreteType();
// If both sides of the requirement are concrete, equate them.
if (concreteType1 && concreteType2) {
return addSameTypeRequirementBetweenConcrete(concreteType1,
concreteType2, source,
diagnoseMismatch);
}
// If one side is concrete, map the other side to that concrete type.
if (concreteType1) {
return addSameTypeRequirementToConcrete(type2, concreteType1,
source.getSource(*this, type2));
}
if (concreteType2) {
return addSameTypeRequirementToConcrete(type1, concreteType2,
source.getSource(*this, type1));
}
return addSameTypeRequirementBetweenTypeParameters(
type1, type2,
source.getSource(*this, type2));
}
ConstraintResult GenericSignatureBuilder::addInheritedRequirements(
TypeDecl *decl,
UnresolvedType type,
const RequirementSource *parentSource,
ModuleDecl *inferForModule) {
// Local function to get the source.
auto getFloatingSource = [&](const TypeRepr *typeRepr, bool forInferred) {
if (parentSource) {
if (auto assocType = dyn_cast<AssociatedTypeDecl>(decl)) {
auto proto = assocType->getProtocol();
return FloatingRequirementSource::viaProtocolRequirement(
parentSource, proto, typeRepr, forInferred);
}
auto proto = cast<ProtocolDecl>(decl);
return FloatingRequirementSource::viaProtocolRequirement(
parentSource, proto, typeRepr, forInferred);
}
// We are inferring requirements.
if (forInferred) {
return FloatingRequirementSource::forInferred(typeRepr);
}
// Explicit requirement.
if (typeRepr)
return FloatingRequirementSource::forExplicit(typeRepr);
// An abstract explicit requirement.
return FloatingRequirementSource::forAbstract();
};
auto visitType = [&](Type inheritedType, const TypeRepr *typeRepr) {
if (inferForModule) {
inferRequirements(*inferForModule, inheritedType,
getFloatingSource(typeRepr, /*forInferred=*/true));
}
return addTypeRequirement(
type, inheritedType, getFloatingSource(typeRepr,
/*forInferred=*/false),
UnresolvedHandlingKind::GenerateConstraints, inferForModule);
};
return visitInherited(decl, visitType);
}
ConstraintResult
GenericSignatureBuilder::addRequirement(const Requirement &req,
FloatingRequirementSource source,
ModuleDecl *inferForModule) {
return addRequirement(req, nullptr, source, nullptr, inferForModule);
}
ConstraintResult
GenericSignatureBuilder::addRequirement(const Requirement &req,
const RequirementRepr *reqRepr,
FloatingRequirementSource source,
const SubstitutionMap *subMap,
ModuleDecl *inferForModule) {
// Local substitution for types in the requirement.
auto subst = [&](Type t) {
if (subMap)
return t.subst(*subMap);
return t;
};
auto firstType = subst(req.getFirstType());
switch (req.getKind()) {
case RequirementKind::Superclass:
case RequirementKind::Conformance: {
auto secondType = subst(req.getSecondType());
if (inferForModule) {
inferRequirements(*inferForModule, firstType,
source.asInferred(
RequirementRepr::getFirstTypeRepr(reqRepr)));
inferRequirements(*inferForModule, secondType,
source.asInferred(
RequirementRepr::getSecondTypeRepr(reqRepr)));
}
return addTypeRequirement(firstType, secondType, source,
UnresolvedHandlingKind::GenerateConstraints,
inferForModule);
}
case RequirementKind::Layout: {
if (inferForModule) {
inferRequirements(*inferForModule, firstType,
source.asInferred(
RequirementRepr::getFirstTypeRepr(reqRepr)));
}
return addLayoutRequirement(firstType, req.getLayoutConstraint(), source,
UnresolvedHandlingKind::GenerateConstraints);
}
case RequirementKind::SameType: {
auto secondType = subst(req.getSecondType());
if (inferForModule) {
inferRequirements(*inferForModule, firstType,
source.asInferred(
RequirementRepr::getFirstTypeRepr(reqRepr)));
inferRequirements(*inferForModule, secondType,
source.asInferred(
RequirementRepr::getSecondTypeRepr(reqRepr)));
}
return addSameTypeRequirement(
firstType, secondType, source,
UnresolvedHandlingKind::GenerateConstraints,
[&](Type type1, Type type2) {
Impl->HadAnyError = true;
if (source.getLoc().isValid() &&
!type1->hasError() &&
!type2->hasError()) {
Diags.diagnose(source.getLoc(), diag::requires_same_concrete_type,
type1, type2);
}
});
}
}
llvm_unreachable("Unhandled requirement?");
}
/// AST walker that infers requirements from type representations.
class GenericSignatureBuilder::InferRequirementsWalker : public TypeWalker {
ModuleDecl &module;
GenericSignatureBuilder &Builder;
FloatingRequirementSource source;
public:
InferRequirementsWalker(ModuleDecl &module,
GenericSignatureBuilder &builder,
FloatingRequirementSource source)
: module(module), Builder(builder), source(source) { }
Action walkToTypePre(Type ty) override {
// Unbound generic types are the result of recovered-but-invalid code, and
// don't have enough info to do any useful substitutions.
if (ty->is<UnboundGenericType>())
return Action::Stop;
return Action::Continue;
}
Action walkToTypePost(Type ty) override {
// Infer from generic typealiases.
if (auto TypeAlias = dyn_cast<TypeAliasType>(ty.getPointer())) {
auto decl = TypeAlias->getDecl();
auto genericSig = decl->getGenericSignature();
if (!genericSig)
return Action::Continue;
auto subMap = TypeAlias->getSubstitutionMap();
for (const auto &rawReq : genericSig->getRequirements()) {
if (auto req = rawReq.subst(subMap))
Builder.addRequirement(*req, source, nullptr);
}
return Action::Continue;
}
// Infer requirements from `@differentiable` function types.
// For all non-`@noDerivative` parameter and result types:
// - `@differentiable`, `@differentiable(_forward)`, or
// `@differentiable(reverse)`: add `T: Differentiable` requirement.
// - `@differentiable(_linear)`: add
// `T: Differentiable`, `T == T.TangentVector` requirements.
if (auto *fnTy = ty->getAs<AnyFunctionType>()) {
auto &ctx = Builder.getASTContext();
auto *differentiableProtocol =
ctx.getProtocol(KnownProtocolKind::Differentiable);
if (differentiableProtocol && fnTy->isDifferentiable()) {
auto addConformanceConstraint = [&](Type type, ProtocolDecl *protocol) {
Requirement req(RequirementKind::Conformance, type,
protocol->getDeclaredInterfaceType());
Builder.addRequirement(req, source, nullptr);
};
auto addSameTypeConstraint = [&](Type firstType,
AssociatedTypeDecl *assocType) {
auto *protocol = assocType->getProtocol();
auto conf = Builder.lookupConformance(CanType(), firstType, protocol);
auto secondType = conf.getAssociatedType(
firstType, assocType->getDeclaredInterfaceType());
Requirement req(RequirementKind::SameType, firstType, secondType);
Builder.addRequirement(req, source, nullptr);
};
auto *tangentVectorAssocType =
differentiableProtocol->getAssociatedType(ctx.Id_TangentVector);
auto addRequirements = [&](Type type, bool isLinear) {
addConformanceConstraint(type, differentiableProtocol);
if (isLinear)
addSameTypeConstraint(type, tangentVectorAssocType);
};
auto constrainParametersAndResult = [&](bool isLinear) {
for (auto &param : fnTy->getParams())
if (!param.isNoDerivative())
addRequirements(param.getPlainType(), isLinear);
addRequirements(fnTy->getResult(), isLinear);
};
// Add requirements.
constrainParametersAndResult(fnTy->getDifferentiabilityKind() ==
DifferentiabilityKind::Linear);
}
}
if (!ty->isSpecialized())
return Action::Continue;
// Infer from generic nominal types.
auto decl = ty->getAnyNominal();
if (!decl) return Action::Continue;
// FIXME: The GSB and the request evaluator both detect a cycle here if we
// force a recursive generic signature. We should look into moving cycle
// detection into the generic signature request(s) - see rdar://55263708
if (!decl->hasComputedGenericSignature())
return Action::Continue;
auto genericSig = decl->getGenericSignature();
if (!genericSig)
return Action::Continue;
/// Retrieve the substitution.
auto subMap = ty->getContextSubstitutionMap(&module, decl);
// Handle the requirements.
// FIXME: Inaccurate TypeReprs.
for (const auto &rawReq : genericSig->getRequirements()) {
if (auto req = rawReq.subst(subMap))
Builder.addRequirement(*req, source, nullptr);
}
return Action::Continue;
}
};
void GenericSignatureBuilder::inferRequirements(
ModuleDecl &module,
Type type,
FloatingRequirementSource source) {
if (!type)
return;
// FIXME: Crummy source-location information.
InferRequirementsWalker walker(module, *this, source);
type.walk(walker);
}
void GenericSignatureBuilder::inferRequirements(
ModuleDecl &module,
ParameterList *params) {
for (auto P : *params) {
inferRequirements(module, P->getInterfaceType(),
FloatingRequirementSource::forInferred(P->getTypeRepr()));
}
}
namespace swift {
template<typename T>
bool operator<(const Constraint<T> &lhs, const Constraint<T> &rhs) {
// FIXME: Awful.
auto lhsSource = lhs.getSubjectDependentType({ });
auto rhsSource = rhs.getSubjectDependentType({ });
if (int result = compareDependentTypes(lhsSource, rhsSource))
return result < 0;
if (int result = lhs.source->compare(rhs.source))
return result < 0;
return false;
}
template<typename T>
bool operator==(const Constraint<T> &lhs, const Constraint<T> &rhs){
return lhs.hasSameSubjectAs(rhs) &&
lhs.value == rhs.value &&
lhs.source == rhs.source;
}
template<>
bool operator==(const Constraint<Type> &lhs, const Constraint<Type> &rhs){
return lhs.hasSameSubjectAs(rhs) &&
lhs.value->isEqual(rhs.value) &&
lhs.source == rhs.source;
}
} // namespace swift
namespace {
/// Retrieve the representative constraint that will be used for diagnostics.
template<typename T>
Optional<Constraint<T>> findRepresentativeConstraint(
GenericSignatureBuilder &builder,
ArrayRef<Constraint<T>> constraints,
RequirementKind kind,
llvm::function_ref<bool(const Constraint<T> &)>
isSuitableRepresentative) {
Optional<Constraint<T>> fallbackConstraint;
// Find a representative constraint.
Optional<Constraint<T>> representativeConstraint;
for (const auto &constraint : constraints) {
// Make sure we have a constraint to fall back on.
if (!fallbackConstraint)
fallbackConstraint = constraint;
// If this isn't a suitable representative constraint, ignore it.
if (!isSuitableRepresentative(constraint))
continue;
// Check whether this constraint is better than the best we've seen so far
// at being the representative constraint against which others will be
// compared.
if (!representativeConstraint) {
representativeConstraint = constraint;
continue;
}
if (kind != RequirementKind::SameType) {
// We prefer non-redundant explicit constraints over everything else.
bool thisIsNonRedundantExplicit =
(!constraint.source->isDerivedNonRootRequirement() &&
!builder.isRedundantExplicitRequirement(
ExplicitRequirement::fromExplicitConstraint(
kind, constraint)));
bool representativeIsNonRedundantExplicit =
(!representativeConstraint->source->isDerivedNonRootRequirement() &&
!builder.isRedundantExplicitRequirement(
ExplicitRequirement::fromExplicitConstraint(
kind, *representativeConstraint)));
if (thisIsNonRedundantExplicit != representativeIsNonRedundantExplicit) {
if (thisIsNonRedundantExplicit)
representativeConstraint = constraint;
continue;
}
}
// We prefer derived constraints to non-derived constraints.
bool thisIsDerived = constraint.source->isDerivedRequirement();
bool representativeIsDerived =
representativeConstraint->source->isDerivedRequirement();
if (thisIsDerived != representativeIsDerived) {
if (thisIsDerived)
representativeConstraint = constraint;
continue;
}
// We prefer constraints that are explicit to inferred constraints.
bool thisIsInferred = constraint.source->isInferredRequirement();
bool representativeIsInferred =
representativeConstraint->source->isInferredRequirement();
if (thisIsInferred != representativeIsInferred) {
if (thisIsInferred)
representativeConstraint = constraint;
continue;
}
// We prefer constraints with locations to constraints without locations.
bool thisHasValidSourceLoc = constraint.source->getLoc().isValid();
bool representativeHasValidSourceLoc =
representativeConstraint->source->getLoc().isValid();
if (thisHasValidSourceLoc != representativeHasValidSourceLoc) {
if (thisHasValidSourceLoc)
representativeConstraint = constraint;
continue;
}
// Otherwise, order via the constraint itself.
if (constraint < *representativeConstraint)
representativeConstraint = constraint;
}
return representativeConstraint ? representativeConstraint
: fallbackConstraint;
}
} // end anonymous namespace
/// For each potential archetype within the given equivalence class that is
/// an associated type, expand the protocol requirements for the enclosing
/// protocol.
static void expandSameTypeConstraints(GenericSignatureBuilder &builder,
EquivalenceClass *equivClass) {
auto genericParams = builder.getGenericParams();
auto existingMembers = equivClass->members;
for (auto pa : existingMembers) {
auto dependentType = pa->getDependentType(genericParams);
for (const auto &conforms : equivClass->conformsTo) {
auto proto = conforms.first;
// Check whether we already have a conformance constraint for this
// potential archetype.
bool alreadyFound = false;
const RequirementSource *conformsSource = nullptr;
for (const auto &constraint : conforms.second) {
if (constraint.source->getAffectedType()->isEqual(dependentType)) {
alreadyFound = true;
break;
}
// Capture the source for later use, skipping
if (!conformsSource &&
constraint.source->kind
!= RequirementSource::RequirementSignatureSelf)
conformsSource = constraint.source;
}
if (alreadyFound) continue;
if (!conformsSource) continue;
// Pick a source at random and reseat it on this potential archetype.
auto source = conformsSource->viaEquivalentType(builder, dependentType);
// Expand same-type constraints.
builder.expandConformanceRequirement(pa, proto, source,
/*onlySameTypeConstraints=*/true);
}
}
}
static bool compareSourceLocs(SourceManager &SM, SourceLoc lhsLoc, SourceLoc rhsLoc) {
if (lhsLoc.isValid() != rhsLoc.isValid())
return lhsLoc.isValid();
if (lhsLoc.isValid() && rhsLoc.isValid()) {
unsigned lhsBuffer = SM.findBufferContainingLoc(lhsLoc);
unsigned rhsBuffer = SM.findBufferContainingLoc(rhsLoc);
// If the buffers are the same, use source location ordering.
if (lhsBuffer == rhsBuffer) {
if (SM.isBeforeInBuffer(lhsLoc, rhsLoc))
return true;
} else {
// Otherwise, order by buffer identifier.
if (SM.getIdentifierForBuffer(lhsBuffer)
.compare(SM.getIdentifierForBuffer(lhsBuffer)))
return true;
}
}
return false;
}
/// A directed graph where the vertices are explicit requirement sources and
/// an edge (v, w) records that the explicit source v implies the explicit
/// source w.
///
/// The roots of the strongly connected component graph are the basic set of
/// explicit requirements which imply everything else. We pick the best
/// representative from each root strongly connected component to form the
/// final set of non-redundant explicit requirements.
class RedundantRequirementGraph {
/// 2**16 explicit requirements ought to be enough for everybody.
using VertexID = uint16_t;
using ComponentID = uint16_t;
struct Vertex {
ExplicitRequirement req;
explicit Vertex(ExplicitRequirement req) : req(req) {}
/// The SCC that this vertex belongs to.
ComponentID component = UndefinedComponent;
/// State for the SCC algorithm.
VertexID index = UndefinedIndex;
VertexID lowLink = -1;
bool onStack = false;
/// Outgoing edges.
SmallVector<VertexID, 1> successors;
#ifndef NDEBUG
bool sawVertex = false;
#endif
static const ComponentID UndefinedComponent = -1;
static const VertexID UndefinedIndex = -1;
};
/// Maps each requirement source to a unique 16-bit ID.
llvm::SmallDenseMap<ExplicitRequirement, VertexID, 2> reqs;
SmallVector<Vertex, 2> vertices;
ComponentID componentCount = 0;
VertexID vertexCount = 0;
SmallVector<VertexID, 2> stack;
public:
template<typename T, typename Fn>
void addConstraintsFromEquivClass(
GenericSignatureBuilder &builder,
const std::vector<Constraint<T>> &constraints,
RequirementKind kind,
Fn filter) {
// The set of 'redundant explicit requirements', which are known to be less
// specific than some other explicit requirements. An example is a type
// parameter with multiple superclass constraints:
//
// class A {}
// class B : A {}
// class C : B {}
//
// func f<T>(_: T) where T : A, T : B, T : C {}
//
// 'T : C' supercedes 'T : A' and 'T : B', because C is a subclass of
// 'A' and 'B'.
SmallVector<ExplicitRequirement, 1> redundantExplicitReqs;
// The set of all other explicit requirements, which are known to be the most
// specific. These imply the less specific 'redundant explicit sources'
// above.
//
// Also, if there is more than one most specific explicit requirements, they
// all imply each other.
SmallVector<ExplicitRequirement, 1> explicitReqs;
// The set of root explicit requirements for each derived requirements.
//
// These 'root requirements' imply the 'explicit requirements'.
SmallVector<ExplicitRequirement, 1> rootReqs;
for (auto constraint : constraints) {
auto *source = constraint.source;
if (source->isDerivedNonRootRequirement()) {
// If the derived requirement was filtered by our predicate, it doesn't
// make our explicit requirements redundant.
if (filter(constraint))
continue;
auto req = ExplicitRequirement::fromDerivedConstraint(kind, constraint);
rootReqs.push_back(req);
} else {
auto req = ExplicitRequirement::fromExplicitConstraint(kind, constraint);
VertexID v = addVertex(req);
#ifndef NDEBUG
// Record that we saw an actual explicit requirement rooted at this vertex,
// for verification purposes.
vertices[v].sawVertex = true;
#endif
(void) v;
// If the explicit requirement was filtered by our predicate, it doesn't
// make the other explicit requirements redundant.
if (filter(constraint)) {
redundantExplicitReqs.push_back(req);
} else {
explicitReqs.push_back(req);
}
}
}
// If all requirements are derived, there is nothing to do.
if (explicitReqs.empty()) {
if (!redundantExplicitReqs.empty()) {
assert(!rootReqs.empty());
for (auto rootReq : rootReqs) {
for (auto redundantReq : redundantExplicitReqs) {
addEdge(rootReq, redundantReq);
}
}
}
return;
}
// If there are multiple most specific explicit requirements, they will form a cycle.
if (explicitReqs.size() > 1) {
for (unsigned index : indices(explicitReqs)) {
auto firstReq = explicitReqs[index];
auto secondReq = explicitReqs[(index + 1) % explicitReqs.size()];
addEdge(firstReq, secondReq);
}
}
// The cycle of most specific explicit requirements implies all less specific
// explicit requirements.
for (auto redundantReq : redundantExplicitReqs) {
addEdge(explicitReqs[0], redundantReq);
}
// The root explicit requirement of each derived requirement implies the cycle of
// most specific explicit requirements.
for (auto rootReq : rootReqs) {
addEdge(rootReq, explicitReqs[0]);
}
}
private:
/// If we haven't seen this requirement yet, add it and
/// return a new ID. Otherwise, return an existing ID.
VertexID addVertex(ExplicitRequirement req) {
assert(!req.getSource()->isDerivedNonRootRequirement());
VertexID id = vertices.size();
// Check for wrap-around.
if (id != vertices.size()) {
llvm::errs() << "Too many explicit requirements";
abort();
}
assert(reqs.size() == vertices.size());
auto inserted = reqs.insert(std::make_pair(req, id));
// Check if we've already seen this vertex.
if (!inserted.second)
return inserted.first->second;
vertices.emplace_back(req);
return id;
}
/// Add a directed edge from one requirement to another.
/// If we haven't seen either requirement yet, we add a
/// new vertex; this allows visiting equivalence classes in
/// a single pass, without having to build the set of vertices
/// first.
void addEdge(ExplicitRequirement fromReq,
ExplicitRequirement toReq) {
assert(!fromReq.getSource()->isDerivedNonRootRequirement());
assert(!toReq.getSource()->isDerivedNonRootRequirement());
VertexID from = addVertex(fromReq);
VertexID to = addVertex(toReq);
vertices[from].successors.push_back(to);
}
/// Tarjan's algorithm.
void computeSCCs() {
for (VertexID v : indices(vertices)) {
if (vertices[v].index == Vertex::UndefinedIndex)
strongConnect(v);
}
}
void strongConnect(VertexID v) {
// Set the depth index for v to the smallest unused index.
assert(vertices[v].index == Vertex::UndefinedIndex);
vertices[v].index = vertexCount;
assert(vertices[v].lowLink == Vertex::UndefinedIndex);
vertices[v].lowLink = vertexCount;
vertexCount++;
stack.push_back(v);
assert(!vertices[v].onStack);
vertices[v].onStack = true;
// Consider successors of v.
for (VertexID w : vertices[v].successors) {
if (vertices[w].index == Vertex::UndefinedIndex) {
// Successor w has not yet been visited; recurse on it.
strongConnect(w);
assert(vertices[w].lowLink != Vertex::UndefinedIndex);
vertices[v].lowLink = std::min(vertices[v].lowLink,
vertices[w].lowLink);
} else if (vertices[w].onStack) {
// Successor w is in stack S and hence in the current SCC.
//
// If w is not on stack, then (v, w) is an edge pointing
// to an SCC already found and must be ignored.
assert(vertices[w].lowLink != Vertex::UndefinedIndex);
vertices[v].lowLink = std::min(vertices[v].lowLink,
vertices[w].index);
}
}
// If v is a root node, pop the stack and generate an SCC.
if (vertices[v].lowLink == vertices[v].index) {
VertexID w = Vertex::UndefinedIndex;
do {
w = stack.back();
assert(vertices[w].onStack);
stack.pop_back();
vertices[w].onStack = false;
assert(vertices[w].component == Vertex::UndefinedComponent);
vertices[w].component = componentCount;
} while (v != w);
componentCount++;
}
}
public:
using RedundantRequirementMap =
llvm::DenseMap<ExplicitRequirement,
llvm::SmallDenseSet<ExplicitRequirement, 2>>;
void computeRedundantRequirements(SourceManager &SM,
RedundantRequirementMap &redundant) {
// First, compute SCCs.
computeSCCs();
// The set of edges pointing to each connected component.
SmallVector<SmallVector<ComponentID, 2>, 2> inboundComponentEdges;
inboundComponentEdges.resize(componentCount);
// The set of edges originating from this connected component.
SmallVector<SmallVector<ComponentID, 2>, 2> outboundComponentEdges;
outboundComponentEdges.resize(componentCount);
// Visit all vertices and build the adjacency sets for the connected
// component graph.
for (const auto &vertex : vertices) {
assert(vertex.component != Vertex::UndefinedComponent);
for (auto successor : vertex.successors) {
ComponentID otherComponent = vertices[successor].component;
if (vertex.component != otherComponent) {
inboundComponentEdges[otherComponent].push_back(vertex.component);
outboundComponentEdges[vertex.component].push_back(otherComponent);
}
}
}
auto isRootComponent = [&](ComponentID component) -> bool {
return inboundComponentEdges[component].empty();
};
// The set of root components.
llvm::SmallDenseSet<ComponentID, 2> rootComponents;
// The best explicit requirement for each root component.
SmallVector<Optional<ExplicitRequirement>, 2> bestExplicitReq;
bestExplicitReq.resize(componentCount);
// Visit all vertices and find the best requirement for each root component.
for (const auto &vertex : vertices) {
if (isRootComponent(vertex.component)) {
rootComponents.insert(vertex.component);
// If this vertex is part of a root SCC, see if the requirement is
// better than the one we have so far.
auto &best = bestExplicitReq[vertex.component];
if (isBetterExplicitRequirement(SM, best, vertex.req))
best = vertex.req;
}
}
// The set of root components that each component is reachable from.
SmallVector<llvm::SmallDenseSet<ComponentID, 2>, 2> reachableFromRoot;
reachableFromRoot.resize(componentCount);
// Traverse the graph of connected components starting from the roots.
for (auto rootComponent : rootComponents) {
SmallVector<ComponentID, 2> worklist;
auto addToWorklist = [&](ComponentID nextComponent) {
if (!reachableFromRoot[nextComponent].count(rootComponent))
worklist.push_back(nextComponent);
};
addToWorklist(rootComponent);
while (!worklist.empty()) {
auto component = worklist.back();
worklist.pop_back();
reachableFromRoot[component].insert(rootComponent);
for (auto nextComponent : outboundComponentEdges[component])
addToWorklist(nextComponent);
}
}
// Compute the mapping of redundant requirements to the best root
// requirement that implies them.
for (const auto &vertex : vertices) {
if (isRootComponent(vertex.component)) {
// A root component is reachable from itself, and itself only.
assert(reachableFromRoot[vertex.component].size() == 1);
assert(reachableFromRoot[vertex.component].count(vertex.component) == 1);
} else {
assert(!bestExplicitReq[vertex.component].hasValue() &&
"Recorded best requirement for non-root SCC?");
}
// We have a non-root component. This requirement is always
// redundant.
auto reachableFromRootSet = reachableFromRoot[vertex.component];
assert(reachableFromRootSet.size() > 0);
for (auto rootComponent : reachableFromRootSet) {
assert(isRootComponent(rootComponent));
auto best = bestExplicitReq[rootComponent];
assert(best.hasValue() &&
"Did not record best requirement for root SCC?");
assert(vertex.req != *best || vertex.component == rootComponent);
if (vertex.req != *best) {
redundant[vertex.req].insert(*best);
}
}
}
}
private:
bool isBetterExplicitRequirement(SourceManager &SM,
Optional<ExplicitRequirement> optExisting,
ExplicitRequirement current) {
if (!optExisting.hasValue())
return true;
auto existing = *optExisting;
auto *existingSource = existing.getSource();
auto *currentSource = current.getSource();
// Prefer explicit sources over inferred ones, so that you can
// write either of the following without a warning:
//
// func foo<T>(_: Set<T>) {}
// func foo<T : Hashable>(_: Set<T>) {}
bool existingInferred = existingSource->isInferredRequirement();
bool currentInferred = currentSource->isInferredRequirement();
if (existingInferred != currentInferred)
return currentInferred;
// Prefer a RequirementSignatureSelf over anything else.
if ((currentSource->kind == RequirementSource::RequirementSignatureSelf) ||
(existingSource->kind == RequirementSource::RequirementSignatureSelf))
return (currentSource->kind == RequirementSource::RequirementSignatureSelf);
// Prefer sources with a shorter type.
auto existingType = existingSource->getStoredType();
auto currentType = currentSource->getStoredType();
int cmpTypes = compareDependentTypes(currentType, existingType);
if (cmpTypes != 0)
return cmpTypes < 0;
auto existingLoc = existingSource->getLoc();
auto currentLoc = currentSource->getLoc();
return compareSourceLocs(SM, currentLoc, existingLoc);
}
public:
void dump(llvm::raw_ostream &out, SourceManager *SM) const {
out << "* Vertices:\n";
for (const auto &vertex : vertices) {
out << "Component " << vertex.component << ", ";
vertex.req.dump(out, SM);
out << "\n";
}
out << "* Edges:\n";
for (const auto &from : vertices) {
for (VertexID w : from.successors) {
const auto &to = vertices[w];
from.req.dump(out, SM);
out << " -> ";
to.req.dump(out, SM);
out << "\n";
}
}
}
#ifndef NDEBUG
void verifyAllVerticesWereSeen(SourceManager *SM) const {
for (const auto &vertex : vertices) {
if (!vertex.sawVertex) {
// We found a vertex that was referenced by an edge, but was
// never added explicitly. This means we have a derived
// requirement rooted at the source, but we never saw the
// corresponding explicit requirement. This should not happen.
llvm::errs() << "Found an orphaned vertex:\n";
vertex.req.dump(llvm::errs(), SM);
llvm::errs() << "\nRedundant requirement graph:\n";
dump(llvm::errs(), SM);
abort();
}
}
}
#endif
};
void GenericSignatureBuilder::ExplicitRequirement::dump(
llvm::raw_ostream &out, SourceManager *SM) const {
switch (getKind()) {
case RequirementKind::Conformance:
out << "conforms_to: ";
break;
case RequirementKind::Layout:
out << "layout: ";
break;
case RequirementKind::Superclass:
out << "superclass: ";
break;
case RequirementKind::SameType:
out << "same_type: ";
break;
}
getSource()->dump(out, SM, 0);
out << " : ";
if (auto type = rhs.dyn_cast<Type>())
out << type;
else if (auto *proto = rhs.dyn_cast<ProtocolDecl *>())
out << proto->getName();
else
out << rhs.get<LayoutConstraint>();
}
void GenericSignatureBuilder::computeRedundantRequirements() {
assert(!Impl->computedRedundantRequirements &&
"Already computed redundant requirements");
#ifndef NDEBUG
Impl->computedRedundantRequirements = true;
#endif
RedundantRequirementGraph graph;
// Visit each equivalence class, recording all explicit requirement sources,
// and the root of each derived requirement source that implies an explicit
// source.
for (auto &equivClass : Impl->EquivalenceClasses) {
for (auto &entry : equivClass.conformsTo) {
graph.addConstraintsFromEquivClass(
*this, entry.second,
RequirementKind::Conformance,
[&](Constraint<ProtocolDecl *> constraint) -> bool {
auto *source = constraint.source;
bool derivedViaConcrete = false;
if (source->getMinimalConformanceSource(
*this, constraint.getSubjectDependentType({ }), entry.first,
derivedViaConcrete)
!= source)
return true;
if (derivedViaConcrete)
return true;
return false;
});
}
if (equivClass.concreteType) {
Type resolvedConcreteType =
getCanonicalTypeInContext(equivClass.concreteType, { });
graph.addConstraintsFromEquivClass(
*this, equivClass.concreteTypeConstraints,
RequirementKind::SameType,
[&](Constraint<Type> constraint) -> bool {
auto *source = constraint.source;
Type t = constraint.value;
bool derivedViaConcrete = false;
if (source->getMinimalConformanceSource(
*this, constraint.getSubjectDependentType({ }), nullptr,
derivedViaConcrete)
!= source)
return true;
if (derivedViaConcrete)
return true;
if (t->isEqual(resolvedConcreteType))
return false;
auto resolvedType = getCanonicalTypeInContext(t, { });
if (resolvedType->isEqual(resolvedConcreteType))
return false;
// We have a less-specific constraint.
return true;
});
}
if (equivClass.superclass) {
// Resolve any thus-far-unresolved dependent types.
Type resolvedSuperclass =
getCanonicalTypeInContext(equivClass.superclass, { });
graph.addConstraintsFromEquivClass(
*this, equivClass.superclassConstraints,
RequirementKind::Superclass,
[&](Constraint<Type> constraint) -> bool {
auto *source = constraint.source;
Type t = constraint.value;
bool derivedViaConcrete = false;
if (source->getMinimalConformanceSource(
*this, constraint.getSubjectDependentType({ }), nullptr,
derivedViaConcrete)
!= source)
return true;
if (derivedViaConcrete)
return true;
if (t->isEqual(resolvedSuperclass))
return false;
Type resolvedType = getCanonicalTypeInContext(t, { });
if (resolvedType->isEqual(resolvedSuperclass))
return false;
// We have a less-specific constraint.
return true;
});
}
if (equivClass.layout) {
graph.addConstraintsFromEquivClass(
*this, equivClass.layoutConstraints,
RequirementKind::Layout,
[&](Constraint<LayoutConstraint> constraint) -> bool {
auto *source = constraint.source;
auto layout = constraint.value;
bool derivedViaConcrete = false;
if (source->getMinimalConformanceSource(
*this, constraint.getSubjectDependentType({ }), nullptr,
derivedViaConcrete)
!= source)
return true;
if (derivedViaConcrete)
return true;
return layout != equivClass.layout;
});
}
}
auto &SM = getASTContext().SourceMgr;
#ifndef NDEBUG
graph.verifyAllVerticesWereSeen(&SM);
#endif
// Determine which explicit requirement sources are actually redundant.
assert(Impl->RedundantRequirements.empty());
graph.computeRedundantRequirements(SM, Impl->RedundantRequirements);
}
void
GenericSignatureBuilder::finalize(TypeArrayView<GenericTypeParamType> genericParams,
bool allowConcreteGenericParams) {
// Process any delayed requirements that we can handle now.
processDelayedRequirements();
computeRedundantRequirements();
diagnoseRedundantRequirements();
assert(!Impl->finalized && "Already finalized builder");
#ifndef NDEBUG
Impl->finalized = true;
#endif
// Local function (+ cache) describing the set of equivalence classes
// directly referenced by the concrete same-type constraint of the given
// equivalence class.
llvm::DenseMap<EquivalenceClass *,
SmallPtrSet<EquivalenceClass *, 4>> concreteEquivClasses;
auto getConcreteReferencedEquivClasses
= [&](EquivalenceClass *equivClass)
-> SmallPtrSet<EquivalenceClass *, 4> {
auto known = concreteEquivClasses.find(equivClass);
if (known != concreteEquivClasses.end())
return known->second;
SmallPtrSet<EquivalenceClass *, 4> referencedEquivClasses;
if (!equivClass->concreteType ||
!equivClass->concreteType->hasTypeParameter())
return referencedEquivClasses;
equivClass->concreteType.visit([&](Type type) {
if (type->isTypeParameter()) {
if (auto referencedEquivClass =
resolveEquivalenceClass(type,
ArchetypeResolutionKind::AlreadyKnown)) {
referencedEquivClasses.insert(referencedEquivClass);
}
}
});
concreteEquivClasses[equivClass] = referencedEquivClasses;
return referencedEquivClasses;
};
/// Check whether the given type references the archetype.
auto isRecursiveConcreteType = [&](EquivalenceClass *equivClass,
bool isSuperclass) {
SmallPtrSet<EquivalenceClass *, 4> visited;
SmallVector<EquivalenceClass *, 4> stack;
stack.push_back(equivClass);
visited.insert(equivClass);
// Check whether the specific type introduces recursion.
auto checkTypeRecursion = [&](Type type) {
if (!type->hasTypeParameter()) return false;
return type.findIf([&](Type type) {
if (type->isTypeParameter()) {
if (auto referencedEquivClass =
resolveEquivalenceClass(
type,
ArchetypeResolutionKind::AlreadyKnown)) {
if (referencedEquivClass == equivClass) return true;
if (visited.insert(referencedEquivClass).second)
stack.push_back(referencedEquivClass);
}
}
return false;
});
};
while (!stack.empty()) {
auto currentEquivClass = stack.back();
stack.pop_back();
// If we're checking superclasses, do so now.
if (isSuperclass && currentEquivClass->superclass &&
checkTypeRecursion(currentEquivClass->superclass)) {
return true;
}
// Otherwise, look for the equivalence classes referenced by
// same-type constraints.
for (auto referencedEquivClass :
getConcreteReferencedEquivClasses(currentEquivClass)) {
// If we found a reference to the original archetype, it's recursive.
if (referencedEquivClass == equivClass) return true;
if (visited.insert(referencedEquivClass).second)
stack.push_back(referencedEquivClass);
}
}
return false;
};
// Check for recursive or conflicting same-type bindings and superclass
// constraints.
for (auto &equivClass : Impl->EquivalenceClasses) {
if (equivClass.concreteType) {
// Check for recursive same-type bindings.
if (isRecursiveConcreteType(&equivClass, /*isSuperclass=*/false)) {
if (auto constraint =
equivClass.findAnyConcreteConstraintAsWritten()) {
Impl->HadAnyError = true;
Diags.diagnose(constraint->source->getLoc(),
diag::recursive_same_type_constraint,
constraint->getSubjectDependentType(genericParams),
constraint->value);
}
equivClass.recursiveConcreteType = true;
} else {
checkConcreteTypeConstraints(genericParams, &equivClass);
}
}
// Check for recursive superclass bindings.
if (equivClass.superclass) {
if (isRecursiveConcreteType(&equivClass, /*isSuperclass=*/true)) {
if (auto source = equivClass.findAnySuperclassConstraintAsWritten()) {
Impl->HadAnyError = true;
Diags.diagnose(source->source->getLoc(),
diag::recursive_superclass_constraint,
source->getSubjectDependentType(genericParams),
equivClass.superclass);
}
equivClass.recursiveSuperclassType = true;
} else {
checkSuperclassConstraints(genericParams, &equivClass);
}
}
checkConformanceConstraints(genericParams, &equivClass);
checkLayoutConstraints(genericParams, &equivClass);
};
// FIXME: Expand all conformance requirements. This is expensive :(
for (auto &equivClass : Impl->EquivalenceClasses) {
expandSameTypeConstraints(*this, &equivClass);
}
// Check same-type constraints.
for (auto &equivClass : Impl->EquivalenceClasses) {
checkSameTypeConstraints(genericParams, &equivClass);
}
// Check for generic parameters which have been made concrete or equated
// with each other.
if (!allowConcreteGenericParams) {
SmallPtrSet<PotentialArchetype *, 4> visited;
unsigned depth = 0;
for (const auto gp : getGenericParams())
depth = std::max(depth, gp->getDepth());
for (const auto &pa : Impl->PotentialArchetypes) {
auto rep = pa->getRepresentative();
if (pa->getDependentType()->getRootGenericParam()->getDepth() < depth)
continue;
if (!visited.insert(rep).second)
continue;
// Don't allow a generic parameter to be equivalent to a concrete type,
// because then we don't actually have a parameter.
auto equivClass = rep->getOrCreateEquivalenceClass(*this);
if (equivClass->concreteType &&
!equivClass->concreteType->is<ErrorType>()) {
if (auto constraint = equivClass->findAnyConcreteConstraintAsWritten()){
Impl->HadAnyError = true;
Diags.diagnose(constraint->source->getLoc(),
diag::requires_generic_param_made_equal_to_concrete,
rep->getDependentType(genericParams));
}
continue;
}
// Don't allow two generic parameters to be equivalent, because then we
// don't actually have two parameters.
for (auto other : rep->getEquivalenceClassMembers()) {
// If it isn't a generic parameter, skip it.
if (other == pa || !other->isGenericParam()) continue;
// Try to find an exact constraint that matches 'other'.
auto repConstraint =
findRepresentativeConstraint<Type>(
*this,
equivClass->sameTypeConstraints,
RequirementKind::SameType,
[pa, other](const Constraint<Type> &constraint) {
return (constraint.isSubjectEqualTo(pa) &&
constraint.value->isEqual(other->getDependentType())) ||
(constraint.isSubjectEqualTo(other) &&
constraint.value->isEqual(pa->getDependentType()));
});
// Otherwise, just take any old constraint.
if (!repConstraint) {
repConstraint =
findRepresentativeConstraint<Type>(
*this,
equivClass->sameTypeConstraints,
RequirementKind::SameType,
[](const Constraint<Type> &constraint) {
return true;
});
}
if (repConstraint && repConstraint->source->getLoc().isValid()) {
Impl->HadAnyError = true;
Diags.diagnose(repConstraint->source->getLoc(),
diag::requires_generic_params_made_equal,
pa->getDependentType(genericParams),
other->getDependentType(genericParams));
}
break;
}
}
}
// Emit a diagnostic if we recorded any constraints where the constraint
// type was not constrained to a protocol or class. Provide a fix-it if
// allowConcreteGenericParams is true or the subject type is a member type.
if (!invalidIsaConstraints.empty()) {
for (auto constraint : invalidIsaConstraints) {
auto subjectType = constraint.getSubjectDependentType(getGenericParams());
auto constraintType = constraint.value;
auto source = constraint.source;
auto loc = source->getLoc();
Diags.diagnose(loc, diag::requires_conformance_nonprotocol,
subjectType, constraintType);
auto getNameWithoutSelf = [&](std::string subjectTypeName) {
std::string selfSubstring = "Self.";
if (subjectTypeName.rfind(selfSubstring, 0) == 0) {
return subjectTypeName.erase(0, selfSubstring.length());
}
return subjectTypeName;
};
if (allowConcreteGenericParams ||
(subjectType->is<DependentMemberType>() &&
!source->isProtocolRequirement())) {
auto subjectTypeName = subjectType.getString();
auto subjectTypeNameWithoutSelf = getNameWithoutSelf(subjectTypeName);
Diags.diagnose(loc, diag::requires_conformance_nonprotocol_fixit,
subjectTypeNameWithoutSelf, constraintType.getString())
.fixItReplace(loc, " == ");
}
}
invalidIsaConstraints.clear();
}
}
/// Turn a requirement right-hand side into an unresolved type.
static GenericSignatureBuilder::UnresolvedType asUnresolvedType(
GenericSignatureBuilder::UnresolvedRequirementRHS rhs) {
if (auto pa = rhs.dyn_cast<PotentialArchetype *>())
return GenericSignatureBuilder::UnresolvedType(pa);
return GenericSignatureBuilder::UnresolvedType(rhs.get<Type>());
}
void GenericSignatureBuilder::processDelayedRequirements() {
// If we're already up-to-date, do nothing.
if (Impl->Generation == Impl->LastProcessedGeneration) { return; }
// If there are no delayed requirements, do nothing.
if (Impl->DelayedRequirements.empty()) { return; }
if (Impl->ProcessingDelayedRequirements) { return; }
++NumProcessDelayedRequirements;
llvm::SaveAndRestore<bool> processing(Impl->ProcessingDelayedRequirements,
true);
bool anyChanges = false;
SWIFT_DEFER {
Impl->LastProcessedGeneration = Impl->Generation;
if (!anyChanges)
++NumProcessDelayedRequirementsUnchanged;
};
bool anySolved;
do {
// Steal the delayed requirements so we can reprocess them.
anySolved = false;
auto delayed = std::move(Impl->DelayedRequirements);
Impl->DelayedRequirements.clear();
// Process delayed requirements.
for (const auto &req : delayed) {
// Reprocess the delayed requirement.
ConstraintResult reqResult;
switch (req.kind) {
case DelayedRequirement::Type:
reqResult =
addTypeRequirement(req.lhs, asUnresolvedType(req.rhs), req.source,
UnresolvedHandlingKind::GenerateUnresolved,
/*inferForModule=*/nullptr);
break;
case DelayedRequirement::Layout:
reqResult = addLayoutRequirement(
req.lhs, req.rhs.get<LayoutConstraint>(), req.source,
UnresolvedHandlingKind::GenerateUnresolved);
break;
case DelayedRequirement::SameType:
reqResult = addSameTypeRequirement(
req.lhs, asUnresolvedType(req.rhs), req.source,
UnresolvedHandlingKind::GenerateUnresolved);
break;
}
// Update our state based on what happened.
switch (reqResult) {
case ConstraintResult::Concrete:
++NumDelayedRequirementConcrete;
anySolved = true;
break;
case ConstraintResult::Conflicting:
anySolved = true;
break;
case ConstraintResult::Resolved:
++NumDelayedRequirementResolved;
anySolved = true;
break;
case ConstraintResult::Unresolved:
// Add the requirement back.
++NumDelayedRequirementUnresolved;
break;
}
}
if (anySolved) {
anyChanges = true;
}
} while (anySolved);
}
template<typename T>
Constraint<T> GenericSignatureBuilder::checkConstraintList(
TypeArrayView<GenericTypeParamType> genericParams,
std::vector<Constraint<T>> &constraints,
RequirementKind kind,
llvm::function_ref<bool(const Constraint<T> &)>
isSuitableRepresentative,
llvm::function_ref<
ConstraintRelation(const Constraint<T>&)>
checkConstraint,
Optional<Diag<unsigned, Type, T, T>>
conflictingDiag,
Diag<Type, T> redundancyDiag,
Diag<unsigned, Type, T> otherNoteDiag) {
return checkConstraintList<T, T>(genericParams, constraints, kind,
isSuitableRepresentative, checkConstraint,
conflictingDiag, redundancyDiag,
otherNoteDiag,
[](const T& value) { return value; },
/*removeSelfDerived=*/true);
}
namespace {
/// Remove self-derived sources from the given vector of constraints.
///
/// \returns true if any derived-via-concrete constraints were found.
template<typename T>
bool removeSelfDerived(GenericSignatureBuilder &builder,
std::vector<Constraint<T>> &constraints,
ProtocolDecl *proto,
bool dropDerivedViaConcrete = true,
bool allCanBeSelfDerived = false) {
auto genericParams = builder.getGenericParams();
bool anyDerivedViaConcrete = false;
Optional<Constraint<T>> remainingConcrete;
SmallVector<Constraint<T>, 4> minimalSources;
constraints.erase(
std::remove_if(constraints.begin(), constraints.end(),
[&](const Constraint<T> &constraint) {
bool derivedViaConcrete;
auto minimalSource =
constraint.source->getMinimalConformanceSource(
builder,
constraint.getSubjectDependentType(genericParams),
proto, derivedViaConcrete);
if (minimalSource != constraint.source) {
// The minimal source is smaller than the original source, so the
// original source is self-derived.
++NumSelfDerived;
if (minimalSource) {
// Record a constraint with a minimized source.
minimalSources.push_back(
{constraint.subject,
constraint.value,
minimalSource});
}
return true;
}
if (!derivedViaConcrete)
return false;
anyDerivedViaConcrete = true;
if (!dropDerivedViaConcrete)
return false;
// Drop derived-via-concrete requirements.
if (!remainingConcrete)
remainingConcrete = constraint;
++NumSelfDerived;
return true;
}),
constraints.end());
// If we found any minimal sources, add them now, avoiding introducing any
// redundant sources.
if (!minimalSources.empty()) {
// Collect the sources we already know about.
SmallPtrSet<const RequirementSource *, 4> sources;
for (const auto &constraint : constraints) {
sources.insert(constraint.source);
}
// Add any minimal sources we didn't know about.
for (const auto &minimalSource : minimalSources) {
if (sources.insert(minimalSource.source).second) {
constraints.push_back(minimalSource);
}
}
}
// If we only had concrete conformances, put one back.
if (constraints.empty() && remainingConcrete)
constraints.push_back(*remainingConcrete);
assert((!constraints.empty() || allCanBeSelfDerived) &&
"All constraints were self-derived!");
return anyDerivedViaConcrete;
}
} // end anonymous namespace
template<typename T, typename DiagT>
Constraint<T> GenericSignatureBuilder::checkConstraintList(
TypeArrayView<GenericTypeParamType> genericParams,
std::vector<Constraint<T>> &constraints,
RequirementKind kind,
llvm::function_ref<bool(const Constraint<T> &)>
isSuitableRepresentative,
llvm::function_ref<
ConstraintRelation(const Constraint<T>&)>
checkConstraint,
Optional<Diag<unsigned, Type, DiagT, DiagT>>
conflictingDiag,
Diag<Type, DiagT> redundancyDiag,
Diag<unsigned, Type, DiagT> otherNoteDiag,
llvm::function_ref<DiagT(const T&)> diagValue,
bool removeSelfDerived) {
assert(!constraints.empty() && "No constraints?");
if (removeSelfDerived) {
::removeSelfDerived(*this, constraints, /*proto=*/nullptr);
}
// Sort the constraints, so we get a deterministic ordering of diagnostics.
std::sort(constraints.begin(), constraints.end());
// Find a representative constraint.
auto representativeConstraint =
findRepresentativeConstraint<T>(*this, constraints, kind,
isSuitableRepresentative);
// Local function to provide a note describing the representative constraint.
auto noteRepresentativeConstraint = [&] {
if (representativeConstraint->source->getLoc().isInvalid()) return;
Diags.diagnose(representativeConstraint->source->getLoc(),
otherNoteDiag,
representativeConstraint->source->classifyDiagKind(),
representativeConstraint->getSubjectDependentType(
genericParams),
diagValue(representativeConstraint->value));
};
// Go through the concrete constraints looking for redundancies.
bool diagnosedConflictingRepresentative = false;
for (const auto &constraint : constraints) {
// Leave the representative alone.
if (representativeConstraint && constraint == *representativeConstraint)
continue;
switch (checkConstraint(constraint)) {
case ConstraintRelation::Unrelated:
continue;
case ConstraintRelation::Conflicting: {
// Figure out what kind of subject we have; it will affect the
// diagnostic.
auto getSubjectType =
[&](Type subjectType) -> std::pair<unsigned, Type> {
unsigned kind;
if (auto gp = subjectType->getAs<GenericTypeParamType>()) {
if (gp->getDecl() &&
isa<ProtocolDecl>(gp->getDecl()->getDeclContext())) {
kind = 1;
subjectType = cast<ProtocolDecl>(gp->getDecl()->getDeclContext())
->getDeclaredInterfaceType();
} else {
kind = 0;
}
} else {
kind = 2;
}
return std::make_pair(kind, subjectType);
};
// The requirement conflicts. If this constraint has a location, complain
// about it.
if (constraint.source->getLoc().isValid()) {
Impl->HadAnyError = true;
auto subject =
getSubjectType(constraint.getSubjectDependentType(genericParams));
Diags.diagnose(constraint.source->getLoc(), *conflictingDiag,
subject.first, subject.second,
diagValue(constraint.value),
diagValue(representativeConstraint->value));
noteRepresentativeConstraint();
break;
}
// If the representative itself conflicts and we haven't diagnosed it yet,
// do so now.
if (!diagnosedConflictingRepresentative &&
representativeConstraint->source->getLoc().isValid()) {
Impl->HadAnyError = true;
auto subject =
getSubjectType(
representativeConstraint->getSubjectDependentType(genericParams));
Diags.diagnose(representativeConstraint->source->getLoc(),
*conflictingDiag,
subject.first, subject.second,
diagValue(representativeConstraint->value),
diagValue(constraint.value));
diagnosedConflictingRepresentative = true;
break;
}
break;
}
case ConstraintRelation::Redundant:
// If this requirement is not derived or inferred (but has a useful
// location) complain that it is redundant.
if (constraint.source->shouldDiagnoseRedundancy(true) &&
representativeConstraint &&
representativeConstraint->source->shouldDiagnoseRedundancy(false)) {
Diags.diagnose(constraint.source->getLoc(),
redundancyDiag,
constraint.getSubjectDependentType(genericParams),
diagValue(constraint.value));
noteRepresentativeConstraint();
}
break;
}
}
return *representativeConstraint;
}
/// Determine whether this is a redundantly inheritable Objective-C protocol.
///
/// A redundantly-inheritable Objective-C protocol is one where we will
/// silently accept a directly-stated redundant conformance to this protocol,
/// and emit this protocol in the list of "inherited" protocols. There are
/// two cases where we allow this:
///
// 1) For a protocol defined in Objective-C, so that we will match Clang's
/// behavior, and
/// 2) For an @objc protocol defined in Swift that directly inherits from
/// JavaScriptCore's JSExport, which depends on this behavior.
static bool isRedundantlyInheritableObjCProtocol(
ProtocolDecl *proto,
const RequirementSource *source) {
if (!proto->isObjC()) return false;
// Only do this for the requirement signature computation.
auto parentSource = source->parent;
if (!parentSource ||
parentSource->kind != RequirementSource::RequirementSignatureSelf)
return false;
// Check the two conditions in which we will suppress the diagnostic and
// emit the redundant inheritance.
auto inheritingProto = parentSource->getProtocolDecl();
if (!inheritingProto->hasClangNode() && !proto->getName().is("JSExport"))
return false;
// If the inheriting protocol already has @_restatedObjCConformance with
// this protocol, we're done.
for (auto *attr : inheritingProto->getAttrs()
.getAttributes<RestatedObjCConformanceAttr>()) {
if (attr->Proto == proto) return true;
}
// Otherwise, add @_restatedObjCConformance.
auto &ctx = proto->getASTContext();
inheritingProto->getAttrs().add(new (ctx) RestatedObjCConformanceAttr(proto));
return true;
}
void GenericSignatureBuilder::checkConformanceConstraints(
TypeArrayView<GenericTypeParamType> genericParams,
EquivalenceClass *equivClass) {
for (auto &entry : equivClass->conformsTo) {
// Remove self-derived constraints.
assert(!entry.second.empty() && "No constraints to work with?");
// Remove any self-derived constraints.
removeSelfDerived(*this, entry.second, entry.first);
}
}
void GenericSignatureBuilder::diagnoseRedundantRequirements() const {
SmallVector<ExplicitRequirement, 2> redundantRequirements;
for (auto pair : Impl->RedundantRequirements) {
auto *source = pair.first.getSource();
// Don't diagnose anything without a source location.
if (source->getLoc().isInvalid())
continue;
// Don't diagnose redundant inferred requirements.
if (source->isInferredRequirement())
continue;
// Don't diagnose explicit requirements that are implied by
// inferred requirements.
if (llvm::all_of(pair.second,
[&](const ExplicitRequirement &otherReq) {
return otherReq.getSource()->isInferredRequirement();
}))
continue;
redundantRequirements.push_back(pair.first);
}
auto &SM = Context.SourceMgr;
std::sort(redundantRequirements.begin(), redundantRequirements.end(),
[&](ExplicitRequirement lhs, ExplicitRequirement rhs) {
return compareSourceLocs(SM,
lhs.getSource()->getLoc(),
rhs.getSource()->getLoc());
});
for (const auto &req : redundantRequirements) {
auto *source = req.getSource();
auto loc = source->getLoc();
assert(loc.isValid());
auto subjectType = getSugaredDependentType(source->getStoredType(),
getGenericParams());
switch (req.getKind()) {
case RequirementKind::Conformance: {
auto *proto = req.getRHS().get<ProtocolDecl *>();
// If this conformance requirement recursively makes a protocol
// conform to itself, don't complain here, because we diagnose
// the circular inheritance elsewhere.
{
auto rootSource = source->getRoot();
if (proto == rootSource->getProtocolDecl() &&
rootSource->kind == RequirementSource::RequirementSignatureSelf &&
rootSource->getRootType()->isEqual(source->getAffectedType())) {
break;
}
}
// If this is a redundantly inherited Objective-C protocol, treat it
// as "unrelated" to silence the warning about the redundant
// conformance.
if (isRedundantlyInheritableObjCProtocol(proto, source))
break;
Context.Diags.diagnose(loc, diag::redundant_conformance_constraint,
subjectType, proto);
for (auto otherReq : Impl->RedundantRequirements[req]) {
auto *otherSource = otherReq.getSource();
auto otherLoc = otherSource->getLoc();
if (otherLoc.isInvalid())
continue;
Context.Diags.diagnose(otherLoc, diag::redundant_conformance_here,
1, subjectType, proto);
}
break;
}
case RequirementKind::Superclass:
case RequirementKind::Layout:
case RequirementKind::SameType:
// TODO
break;
}
}
}
namespace swift {
bool operator<(const DerivedSameTypeComponent &lhs,
const DerivedSameTypeComponent &rhs) {
return compareDependentTypes(lhs.type, rhs.type) < 0;
}
} // namespace swift
/// Find the representative in a simple union-find data structure of
/// integral values.
static unsigned findRepresentative(SmallVectorImpl<unsigned> &parents,
unsigned index) {
if (parents[index] == index) return index;
return parents[index] = findRepresentative(parents, parents[index]);
}
/// Union the same-type components denoted by \c index1 and \c index2.
///
/// \param successThreshold Returns true when two sets have been joined
/// and both representatives are below the threshold. The default of 0
/// is equivalent to \c successThreshold == parents.size().
///
/// \returns \c true if the two components were separate and have now
/// been joined; \c false if they were already in the same set.
static bool unionSets(SmallVectorImpl<unsigned> &parents,
unsigned index1, unsigned index2,
unsigned successThreshold = 0) {
// Find the representatives of each component class.
unsigned rep1 = findRepresentative(parents, index1);
unsigned rep2 = findRepresentative(parents, index2);
if (rep1 == rep2) return false;
// Point at the lowest-numbered representative.
if (rep1 < rep2)
parents[rep2] = rep1;
else
parents[rep1] = rep2;
return (successThreshold == 0) ||
(rep1 < successThreshold && rep2 < successThreshold);
}
/// Computes the ordered set of archetype anchors required to form a minimum
/// spanning tree among the connected components formed by only the derived
/// same-type requirements within the equivalence class \c equivClass.
///
/// The equivalence class contains all potential archetypes that are made
/// equivalent by the known set of same-type constraints, which includes both
/// directly-stated same-type constraints (e.g., \c T.A == T.B) as well as
/// same-type constraints that are implied either because the names coincide
/// (e.g., \c T[.P1].A == T[.P2].A) or due to a requirement in a protocol.
///
/// The equivalence class of the given representative potential archetype
/// (\c rep) is formed from a graph whose vertices are the potential archetypes
/// and whose edges are the same-type constraints. These edges include both
/// directly-stated same-type constraints (e.g., \c T.A == T.B) as well as
/// same-type constraints that are implied either because the names coincide
/// (e.g., \c T[.P1].A == T[.P2].A) or due to a requirement in a protocol.
/// The equivalence class forms a single connected component.
///
/// Within that graph is a subgraph that includes only those edges that are
/// implied (and, therefore, excluding those edges that were explicitly stated).
/// The connected components within that subgraph describe the potential
/// archetypes that would be equivalence even with all of the (explicit)
/// same-type constraints removed.
///
/// The entire equivalence class can be restored by introducing edges between
/// the connected components. This function computes a minimal, canonicalized
/// set of edges (same-type constraints) needed to describe the equivalence
/// class, which is suitable for the generation of the canonical generic
/// signature.
///
/// The resulting set of "edges" is returned as a set of vertices, one per
/// connected component (of the subgraph). Each is the anchor for that
/// connected component (as determined by \c compareDependentTypes()), and the
/// set itself is ordered by \c compareDependentTypes(). The actual set of
/// canonical edges connects vertex i to vertex i+1 for i in 0..<size-1.
static void computeDerivedSameTypeComponents(
GenericSignatureBuilder &builder,
EquivalenceClass *equivClass,
llvm::SmallDenseMap<CanType, unsigned> &componentOf){
// Set up the array of "parents" in the union-find data structure.
llvm::SmallDenseMap<CanType, unsigned> parentIndices;
SmallVector<unsigned, 4> parents;
for (unsigned i : indices(equivClass->members)) {
Type depType = equivClass->members[i]->getDependentType();
parentIndices[depType->getCanonicalType()] = parents.size();
parents.push_back(i);
}
// Walk all of the same-type constraints, performing a union-find operation.
for (const auto &constraint : equivClass->sameTypeConstraints) {
// Treat nested-type-name-match constraints specially.
if (constraint.source->getRoot()->kind ==
RequirementSource::NestedTypeNameMatch)
continue;
// Skip non-derived constraints.
if (!constraint.source->isDerivedRequirement()) continue;
CanType source =
constraint.getSubjectDependentType({ })->getCanonicalType();
CanType target = constraint.value->getCanonicalType();
assert(parentIndices.count(source) == 1 && "Missing source");
assert(parentIndices.count(target) == 1 && "Missing target");
unionSets(parents, parentIndices[source], parentIndices[target]);
}
// Compute and record the components.
auto &components = equivClass->derivedSameTypeComponents;
for (unsigned i : indices(equivClass->members)) {
auto pa = equivClass->members[i];
auto depType = pa->getDependentType();
// Find the representative of this set.
assert(parentIndices.count(depType) == 1 && "Unknown member?");
unsigned index = parentIndices[depType];
unsigned representative = findRepresentative(parents, index);
// If this is the representative, add a component for it.
if (representative == index) {
componentOf[depType] = components.size();
components.push_back(DerivedSameTypeComponent{depType, nullptr});
continue;
}
// This is not the representative; point at the component of the
// representative.
CanType representativeDepTy =
equivClass->members[representative]->getDependentType();
assert(componentOf.count(representativeDepTy) == 1 &&
"Missing representative component?");
unsigned componentIndex = componentOf[representativeDepTy];
componentOf[depType] = componentIndex;
// If this is a better anchor, record it.
if (compareDependentTypes(depType, components[componentIndex].type) < 0) {
components[componentIndex].type = depType;
}
}
// If there is a concrete type, figure out the best concrete type anchor
// per component.
auto genericParams = builder.getGenericParams();
for (const auto &concrete : equivClass->concreteTypeConstraints) {
// Dig out the component associated with constraint.
Type subjectType = concrete.getSubjectDependentType(genericParams);
assert(componentOf.count(subjectType->getCanonicalType()) > 0);
auto &component = components[componentOf[subjectType->getCanonicalType()]];
// FIXME: Skip self-derived sources. This means our attempts to "stage"
// construction of self-derived sources really don't work, because we
// discover more information later, so we need a more on-line or
// iterative approach.
bool derivedViaConcrete;
if (concrete.source->isSelfDerivedSource(builder, subjectType,
derivedViaConcrete))
continue;
// If it has a better source than we'd seen before for this component,
// keep it.
auto &bestConcreteTypeSource = component.concreteTypeSource;
if (!bestConcreteTypeSource ||
concrete.source->compare(bestConcreteTypeSource) < 0)
bestConcreteTypeSource = concrete.source;
}
}
namespace {
/// An edge in the same-type constraint graph that spans two different
/// components.
struct IntercomponentEdge {
unsigned source;
unsigned target;
Constraint<Type> constraint;
bool isSelfDerived = false;
IntercomponentEdge(unsigned source, unsigned target,
const Constraint<Type> &constraint)
: source(source), target(target), constraint(constraint)
{
assert(source != target && "Not an intercomponent edge");
if (this->source > this->target) std::swap(this->source, this->target);
}
friend bool operator<(const IntercomponentEdge &lhs,
const IntercomponentEdge &rhs) {
if (lhs.source != rhs.source)
return lhs.source < rhs.source;
if (lhs.target != rhs.target)
return lhs.target < rhs.target;
// Prefer non-inferred requirement sources.
bool lhsIsInferred = lhs.constraint.source->isInferredRequirement();
bool rhsIsInferred = rhs.constraint.source->isInferredRequirement();
if (lhsIsInferred != rhsIsInferred)
return rhsIsInferred;;
return lhs.constraint < rhs.constraint;
}
SWIFT_DEBUG_DUMP;
};
}
void IntercomponentEdge::dump() const {
llvm::errs() << constraint.getSubjectDependentType({ }).getString() << " -- "
<< constraint.value << ": ";
constraint.source->print(llvm::errs(), nullptr);
llvm::errs() << "\n";
}
/// Determine whether the removal of the given edge will disconnect the
/// nodes \c from and \c to within the given equivalence class.
static bool removalDisconnectsEquivalenceClass(
EquivalenceClass *equivClass,
llvm::SmallDenseMap<CanType, unsigned> &componentOf,
std::vector<IntercomponentEdge> &sameTypeEdges,
unsigned edgeIndex,
CanType fromDepType,
CanType toDepType) {
// Which component are "from" and "to" in within the intercomponent edges?
assert(componentOf.count(fromDepType) > 0);
auto fromComponentIndex = componentOf[fromDepType];
assert(componentOf.count(toDepType) > 0);
auto toComponentIndex = componentOf[toDepType];
// If they're in the same component, they're always connected (due to
// derived edges).
if (fromComponentIndex == toComponentIndex) return false;
/// Describes the parents in the equivalence classes we're forming.
SmallVector<unsigned, 4> parents;
for (unsigned i : range(equivClass->derivedSameTypeComponents.size())) {
parents.push_back(i);
}
for (const auto existingEdgeIndex : indices(sameTypeEdges)) {
if (existingEdgeIndex == edgeIndex) continue;
const auto &edge = sameTypeEdges[existingEdgeIndex];
if (edge.isSelfDerived) continue;
if (unionSets(parents, edge.source, edge.target) &&
findRepresentative(parents, fromComponentIndex) ==
findRepresentative(parents, toComponentIndex))
return false;
}
const auto &edge = sameTypeEdges[edgeIndex];
return !unionSets(parents, edge.source, edge.target) ||
findRepresentative(parents, fromComponentIndex) !=
findRepresentative(parents, toComponentIndex);
}
static AssociatedTypeDecl *takeMemberOfDependentMemberType(Type &type) {
if (auto depMemTy = type->getAs<DependentMemberType>()) {
type = depMemTy->getBase();
return depMemTy->getAssocType();
}
return nullptr;
}
static bool isSelfDerivedNestedTypeNameMatchEdge(
GenericSignatureBuilder &builder,
EquivalenceClass *equivClass,
llvm::SmallDenseMap<CanType, unsigned> &componentOf,
std::vector<IntercomponentEdge> &sameTypeEdges,
unsigned edgeIndex) {
const auto &edge = sameTypeEdges[edgeIndex];
auto genericParams = builder.getGenericParams();
Type sourceType = edge.constraint.getSubjectDependentType(genericParams);
Type target = edge.constraint.value;
DependentMemberType *sourceDepMemTy;
while ((sourceDepMemTy = sourceType->getAs<DependentMemberType>()) &&
sourceDepMemTy->getAssocType() ==
takeMemberOfDependentMemberType(target)) {
sourceType = sourceDepMemTy->getBase();
auto targetEquivClass =
builder.maybeResolveEquivalenceClass(target,
ArchetypeResolutionKind::WellFormed,
false)
.getEquivalenceClassIfPresent();
if (targetEquivClass == equivClass &&
builder.maybeResolveEquivalenceClass(
sourceType,
ArchetypeResolutionKind::WellFormed,
/*wantExactPotentialArchetype=*/false)
.getEquivalenceClass(builder) == equivClass &&
!removalDisconnectsEquivalenceClass(equivClass, componentOf,
sameTypeEdges, edgeIndex,
sourceType->getCanonicalType(),
target->getCanonicalType()))
return true;
}
return false;
}
/// Collapse same-type components using the "delayed" requirements of the
/// equivalence class.
///
/// This operation looks through the delayed requirements within the equivalence
/// class to find paths that connect existing potential archetypes.
static void collapseSameTypeComponentsThroughDelayedRequirements(
EquivalenceClass *equivClass,
llvm::SmallDenseMap<CanType, unsigned> &componentOf,
SmallVectorImpl<unsigned> &collapsedParents,
unsigned &remainingComponents) {
unsigned numCollapsedParents = collapsedParents.size();
/// "Virtual" components for types that aren't resolve to potential
/// archetypes.
llvm::SmallDenseMap<CanType, unsigned> virtualComponents;
/// Retrieve the component for a type representing a virtual component
auto getTypeVirtualComponent = [&](CanType canType) {
auto knownActual = componentOf.find(canType);
if (knownActual != componentOf.end())
return knownActual->second;
auto knownVirtual = virtualComponents.find(canType);
if (knownVirtual != virtualComponents.end())
return knownVirtual->second;
unsigned component = collapsedParents.size();
collapsedParents.push_back(component);
virtualComponents[canType] = component;
return component;
};
/// Retrieve the component for the given potential archetype.
auto getPotentialArchetypeVirtualComponent = [&](PotentialArchetype *pa) {
if (pa->getEquivalenceClassIfPresent() == equivClass)
return getTypeVirtualComponent(pa->getDependentType());
// We found a potential archetype in another equivalence class. Treat it
// as a "virtual" component representing that potential archetype's
// equivalence class.
return getTypeVirtualComponent(
pa->getRepresentative()->getDependentType());
};
for (const auto &delayedReq : equivClass->delayedRequirements) {
// Only consider same-type requirements.
if (delayedReq.kind != DelayedRequirement::SameType) continue;
unsigned lhsComponent;
if (auto lhsPA = delayedReq.lhs.dyn_cast<PotentialArchetype *>())
lhsComponent = getPotentialArchetypeVirtualComponent(lhsPA);
else
lhsComponent = getTypeVirtualComponent(delayedReq.lhs.get<Type>()
->getCanonicalType());
unsigned rhsComponent;
if (auto rhsPA = delayedReq.rhs.dyn_cast<PotentialArchetype *>())
rhsComponent = getPotentialArchetypeVirtualComponent(rhsPA);
else
rhsComponent = getTypeVirtualComponent(delayedReq.rhs.get<Type>()
->getCanonicalType());
// Collapse the sets
if (unionSets(collapsedParents, lhsComponent, rhsComponent,
numCollapsedParents) &&
lhsComponent < numCollapsedParents &&
rhsComponent < numCollapsedParents)
--remainingComponents;
}
/// Remove any additional collapsed parents we added.
collapsedParents.erase(collapsedParents.begin() + numCollapsedParents,
collapsedParents.end());
}
/// Collapse same-type components within an equivalence class, minimizing the
/// number of requirements required to express the equivalence class.
static void collapseSameTypeComponents(
GenericSignatureBuilder &builder,
EquivalenceClass *equivClass,
llvm::SmallDenseMap<CanType, unsigned> &componentOf,
std::vector<IntercomponentEdge> &sameTypeEdges) {
SmallVector<unsigned, 4> collapsedParents;
for (unsigned i : indices(equivClass->derivedSameTypeComponents)) {
collapsedParents.push_back(i);
}
unsigned remainingComponents = equivClass->derivedSameTypeComponents.size();
for (unsigned edgeIndex : indices(sameTypeEdges)) {
auto &edge = sameTypeEdges[edgeIndex];
// If this edge is self-derived, remove it.
if (isSelfDerivedNestedTypeNameMatchEdge(builder, equivClass, componentOf,
sameTypeEdges, edgeIndex)) {
// Note that this edge is self-derived, so we don't consider it again.
edge.isSelfDerived = true;
auto &constraints = equivClass->sameTypeConstraints;
auto known =
std::find_if(constraints.begin(), constraints.end(),
[&](const Constraint<Type> &existing) {
// Check the requirement source, first.
if (existing.source != edge.constraint.source)
return false;
return
(existing.hasSameSubjectAs(edge.constraint) &&
existing.value->isEqual(edge.constraint.value)) ||
(existing.isSubjectEqualTo(edge.constraint.value) &&
edge.constraint.isSubjectEqualTo(existing.value));
});
assert(known != constraints.end());
constraints.erase(known);
continue;
}
// Otherwise, collapse the derived same-type components along this edge,
// because it's derived.
if (unionSets(collapsedParents, edge.source, edge.target))
--remainingComponents;
}
if (remainingComponents > 1) {
// Collapse same-type components by looking at the delayed requirements.
collapseSameTypeComponentsThroughDelayedRequirements(
equivClass, componentOf, collapsedParents, remainingComponents);
}
// If needed, collapse the same-type components merged by a derived
// nested-type-name-match edge.
unsigned maxComponents = equivClass->derivedSameTypeComponents.size();
if (remainingComponents < maxComponents) {
std::vector<DerivedSameTypeComponent> newComponents;
std::vector<unsigned> newIndices(maxComponents, maxComponents);
for (unsigned oldIndex : range(0, maxComponents)) {
auto &oldComponent = equivClass->derivedSameTypeComponents[oldIndex];
unsigned oldRepresentativeIndex =
findRepresentative(collapsedParents, oldIndex);
// If this is the representative, it's a new component; record it.
if (oldRepresentativeIndex == oldIndex) {
assert(newIndices[oldIndex] == maxComponents &&
"Already saw this component?");
unsigned newIndex = newComponents.size();
newIndices[oldIndex] = newIndex;
newComponents.push_back(
{oldComponent.type, oldComponent.concreteTypeSource});
continue;
}
// This is not the representative; merge it into the representative
// component.
auto newRepresentativeIndex = newIndices[oldRepresentativeIndex];
assert(newRepresentativeIndex != maxComponents &&
"Representative should have come earlier");
auto &newComponent = newComponents[newRepresentativeIndex];
// If the old component has a better anchor, keep it.
if (compareDependentTypes(oldComponent.type, newComponent.type) < 0) {
newComponent.type = oldComponent.type;
}
// If the old component has a better concrete type source, keep it.
if (!newComponent.concreteTypeSource ||
(oldComponent.concreteTypeSource &&
oldComponent.concreteTypeSource
->compare(newComponent.concreteTypeSource) < 0))
newComponent.concreteTypeSource = oldComponent.concreteTypeSource;
}
// Move the new results into place.
equivClass->derivedSameTypeComponents = std::move(newComponents);
}
// Sort the components.
llvm::array_pod_sort(equivClass->derivedSameTypeComponents.begin(),
equivClass->derivedSameTypeComponents.end());
}
void GenericSignatureBuilder::checkSameTypeConstraints(
TypeArrayView<GenericTypeParamType> genericParams,
EquivalenceClass *equivClass) {
if (!equivClass->derivedSameTypeComponents.empty())
return;
bool anyDerivedViaConcrete = false;
// Remove self-derived constraints.
if (removeSelfDerived(*this, equivClass->sameTypeConstraints,
/*proto=*/nullptr,
/*dropDerivedViaConcrete=*/false,
/*allCanBeSelfDerived=*/true))
anyDerivedViaConcrete = true;
// Sort the constraints, so we get a deterministic ordering of diagnostics.
llvm::array_pod_sort(equivClass->sameTypeConstraints.begin(),
equivClass->sameTypeConstraints.end());
// Compute the components in the subgraph of the same-type constraint graph
// that includes only derived constraints.
llvm::SmallDenseMap<CanType, unsigned> componentOf;
computeDerivedSameTypeComponents(*this, equivClass, componentOf);
// Go through all of the same-type constraints, collecting all of the
// non-derived constraints to put them into bins: intra-component and
// inter-component.
// Intra-component edges are stored per-component, so we can perform
// diagnostics within each component.
unsigned numComponents = equivClass->derivedSameTypeComponents.size();
std::vector<std::vector<Constraint<Type>>>
intracomponentEdges(numComponents,
std::vector<Constraint<Type>>());
// Intercomponent edges are stored as one big list, which tracks the
// source/target components.
std::vector<IntercomponentEdge> intercomponentEdges;
std::vector<IntercomponentEdge> nestedTypeNameMatchEdges;
for (const auto &constraint : equivClass->sameTypeConstraints) {
// If the source/destination are identical, complain.
if (constraint.isSubjectEqualTo(constraint.value)) {
if (constraint.source->shouldDiagnoseRedundancy(true)) {
Diags.diagnose(constraint.source->getLoc(),
diag::redundant_same_type_constraint,
constraint.getSubjectDependentType(genericParams),
constraint.value);
}
continue;
}
// Determine which component each of the source/destination fall into.
CanType subjectType =
constraint.getSubjectDependentType({ })->getCanonicalType();
assert(componentOf.count(subjectType) > 0 &&
"unknown potential archetype?");
unsigned firstComponentIdx = componentOf[subjectType];
assert(componentOf.count(constraint.value->getCanonicalType()) > 0 &&
"unknown potential archetype?");
unsigned secondComponentIdx =
componentOf[constraint.value->getCanonicalType()];
// Separately track nested-type-name-match constraints.
if (constraint.source->getRoot()->kind ==
RequirementSource::NestedTypeNameMatch) {
// If this is an intercomponent edge, record it separately.
if (firstComponentIdx != secondComponentIdx) {
nestedTypeNameMatchEdges.push_back(
IntercomponentEdge(firstComponentIdx, secondComponentIdx, constraint));
}
continue;
}
// If both vertices are within the same component, this is an
// intra-component edge. Record it as such.
if (firstComponentIdx == secondComponentIdx) {
intracomponentEdges[firstComponentIdx].push_back(constraint);
continue;
}
// Otherwise, it's an intercomponent edge, which is never derived.
assert(!constraint.source->isDerivedRequirement() &&
"Must not be derived");
// Ignore inferred requirements; we don't want to diagnose them.
intercomponentEdges.push_back(
IntercomponentEdge(firstComponentIdx, secondComponentIdx, constraint));
}
// If there were any derived-via-concrete constraints, drop them now before
// we emit other diagnostics.
if (anyDerivedViaConcrete) {
// Remove derived-via-concrete constraints.
(void)removeSelfDerived(*this, equivClass->sameTypeConstraints,
/*proto=*/nullptr,
/*dropDerivedViaConcrete=*/true,
/*allCanBeSelfDerived=*/true);
}
// Walk through each of the components, checking the intracomponent edges.
// This will diagnose any explicitly-specified requirements within a
// component, all of which are redundant.
for (auto &constraints : intracomponentEdges) {
if (constraints.empty()) continue;
checkConstraintList<Type, Type>(
genericParams, constraints, RequirementKind::SameType,
[](const Constraint<Type> &) { return true; },
[](const Constraint<Type> &constraint) {
// Ignore nested-type-name-match constraints.
if (constraint.source->getRoot()->kind ==
RequirementSource::NestedTypeNameMatch)
return ConstraintRelation::Unrelated;
return ConstraintRelation::Redundant;
},
None,
diag::redundant_same_type_constraint,
diag::previous_same_type_constraint,
[&](Type type) {
return type;
},
/*removeSelfDerived=*/false);
}
// Diagnose redundant same-type constraints across components. First,
// sort the edges so that edges that between the same component pairs
// occur next to each other.
llvm::array_pod_sort(intercomponentEdges.begin(), intercomponentEdges.end());
// Diagnose and erase any redundant edges between the same two components.
intercomponentEdges.erase(
std::unique(
intercomponentEdges.begin(), intercomponentEdges.end(),
[&](const IntercomponentEdge &lhs,
const IntercomponentEdge &rhs) {
// If either the source or target is different, we have
// different elements.
if (lhs.source != rhs.source || lhs.target != rhs.target)
return false;
// Check whethe we should diagnose redundancy for both constraints.
if (!lhs.constraint.source->shouldDiagnoseRedundancy(true) ||
!rhs.constraint.source->shouldDiagnoseRedundancy(false))
return true;
Diags.diagnose(lhs.constraint.source->getLoc(),
diag::redundant_same_type_constraint,
lhs.constraint.getSubjectDependentType(genericParams),
lhs.constraint.value);
Diags.diagnose(rhs.constraint.source->getLoc(),
diag::previous_same_type_constraint,
rhs.constraint.source->classifyDiagKind(),
rhs.constraint.getSubjectDependentType(genericParams),
rhs.constraint.value);
return true;
}),
intercomponentEdges.end());
// If we have more intercomponent edges than are needed to form a spanning
// tree, complain about redundancies. Note that the edges we have must
// connect all of the components, or else we wouldn't have an equivalence
// class.
if (intercomponentEdges.size() > numComponents - 1) {
// First let's order all of the intercomponent edges
// as written in source, this helps us to diagnose
// all of the duplicate constraints in correct order.
std::vector<IntercomponentEdge *> sourceOrderedEdges;
for (auto &edge : intercomponentEdges)
sourceOrderedEdges.push_back(&edge);
llvm::array_pod_sort(
sourceOrderedEdges.begin(), sourceOrderedEdges.end(),
[](IntercomponentEdge *const *a, IntercomponentEdge *const *b) -> int {
auto &sourceMgr = (*a)->constraint.value->getASTContext().SourceMgr;
auto locA = (*a)->constraint.source->getLoc();
auto locB = (*b)->constraint.source->getLoc();
// Put invalid locations after valid ones.
if (locA.isInvalid() || locB.isInvalid()) {
if (locA.isInvalid() != locB.isInvalid())
return locA.isValid() ? 1 : -1;
return 0;
}
auto bufferA = sourceMgr.findBufferContainingLoc(locA);
auto bufferB = sourceMgr.findBufferContainingLoc(locB);
if (bufferA != bufferB)
return bufferA < bufferB ? -1 : 1;
auto offsetA = sourceMgr.getLocOffsetInBuffer(locA, bufferA);
auto offsetB = sourceMgr.getLocOffsetInBuffer(locB, bufferB);
return offsetA < offsetB ? -1 : (offsetA == offsetB ? 0 : 1);
});
auto isDiagnosable = [](const IntercomponentEdge &edge, bool isPrimary) {
return edge.constraint.source->shouldDiagnoseRedundancy(isPrimary);
};
using EquivClass = llvm::DenseMap<Type, unsigned>;
llvm::DenseMap<Type, EquivClass> equivalences;
// The idea here is to form an equivalence class per representative
// (picked from each edge constraint in type parameter order) and
// propagate all new equivalent types up the chain until duplicate
// entry is found, that entry is going to point to previous
// declaration and is going to mark current edge as a duplicate of
// such entry.
for (auto edgeIdx : indices(sourceOrderedEdges)) {
const auto &edge = *sourceOrderedEdges[edgeIdx];
Type lhs = edge.constraint.getSubjectDependentType(genericParams);
Type rhs = edge.constraint.value;
// Make sure that representative for equivalence class is picked
// in canonical type parameter order.
if (compareDependentTypes(rhs, lhs) < 0)
std::swap(lhs, rhs);
// Index of the previous declaration of the same-type constraint
// which current edge might be a duplicate of.
Optional<unsigned> previousIndex;
bool isDuplicate = false;
auto &representative = equivalences[lhs];
if (representative.insert({rhs, edgeIdx}).second) {
// Since this is a new equivalence, and right-hand side might
// be a representative of some other equivalence class,
// its existing members have to be merged up.
auto RHSEquivClass = equivalences.find(rhs);
if (RHSEquivClass != equivalences.end()) {
auto &equivClass = RHSEquivClass->getSecond();
representative.insert(equivClass.begin(), equivClass.end());
}
// If left-hand side is involved in any other equivalences
// let's propagate new information up the chain.
for (auto &e : equivalences) {
auto &repr = e.first;
auto &equivClass = e.second;
if (repr->isEqual(lhs) || !equivClass.count(lhs))
continue;
if (!equivClass.insert({rhs, edgeIdx}).second) {
// Even if "previous" edge is not diagnosable we
// still need to produce diagnostic about main duplicate.
isDuplicate = true;
auto prevIdx = equivClass[rhs];
if (!isDiagnosable(intercomponentEdges[prevIdx],
/*isPrimary=*/false))
continue;
// If there is a diagnosable duplicate equivalence,
// it means that we've found our previous declaration.
previousIndex = prevIdx;
break;
}
}
} else {
// Looks like this is a situation like T.A == T.B, ..., T.B == T.A
previousIndex = representative[rhs];
isDuplicate = true;
}
if (!isDuplicate || !isDiagnosable(edge, /*isPrimary=*/true))
continue;
Diags.diagnose(edge.constraint.source->getLoc(),
diag::redundant_same_type_constraint,
edge.constraint.getSubjectDependentType(genericParams),
edge.constraint.value);
if (previousIndex) {
auto &prevEquiv = sourceOrderedEdges[*previousIndex]->constraint;
Diags.diagnose(
prevEquiv.source->getLoc(), diag::previous_same_type_constraint,
prevEquiv.source->classifyDiagKind(),
prevEquiv.getSubjectDependentType(genericParams), prevEquiv.value);
}
}
}
collapseSameTypeComponents(*this, equivClass, componentOf,
nestedTypeNameMatchEdges);
}
void GenericSignatureBuilder::checkConcreteTypeConstraints(
TypeArrayView<GenericTypeParamType> genericParams,
EquivalenceClass *equivClass) {
// Resolve any thus-far-unresolved dependent types.
Type resolvedConcreteType =
getCanonicalTypeInContext(equivClass->concreteType, genericParams);
checkConstraintList<Type>(
genericParams, equivClass->concreteTypeConstraints, RequirementKind::SameType,
[&](const ConcreteConstraint &constraint) {
if (constraint.value->isEqual(resolvedConcreteType))
return true;
auto resolvedType = getCanonicalTypeInContext(constraint.value, { });
return resolvedType->isEqual(resolvedConcreteType);
},
[&](const Constraint<Type> &constraint) {
Type concreteType = constraint.value;
// If the concrete type is equivalent, the constraint is redundant.
if (concreteType->isEqual(equivClass->concreteType))
return ConstraintRelation::Redundant;
// If either has a type parameter or type variable, call them unrelated.
if (concreteType->hasTypeParameter() ||
equivClass->concreteType->hasTypeParameter() ||
concreteType->hasTypeVariable() ||
equivClass->concreteType->hasTypeVariable())
return ConstraintRelation::Unrelated;
return ConstraintRelation::Conflicting;
},
diag::same_type_conflict,
diag::redundant_same_type_to_concrete,
diag::same_type_redundancy_here);
equivClass->concreteType = resolvedConcreteType;
}
void GenericSignatureBuilder::checkSuperclassConstraints(
TypeArrayView<GenericTypeParamType> genericParams,
EquivalenceClass *equivClass) {
assert(equivClass->superclass && "No superclass constraint?");
// Resolve any thus-far-unresolved dependent types.
Type resolvedSuperclass =
getCanonicalTypeInContext(equivClass->superclass, genericParams);
auto representativeConstraint =
checkConstraintList<Type>(
genericParams, equivClass->superclassConstraints, RequirementKind::Superclass,
[&](const ConcreteConstraint &constraint) {
if (constraint.value->isEqual(resolvedSuperclass))
return true;
Type resolvedType =
getCanonicalTypeInContext(constraint.value, { });
return resolvedType->isEqual(resolvedSuperclass);
},
[&](const Constraint<Type> &constraint) {
Type superclass = constraint.value;
// If this class is a superclass of the "best"
if (superclass->isExactSuperclassOf(resolvedSuperclass))
return ConstraintRelation::Redundant;
// Otherwise, it conflicts.
return ConstraintRelation::Conflicting;
},
diag::requires_superclass_conflict,
diag::redundant_superclass_constraint,
diag::superclass_redundancy_here);
// Record the resolved superclass type.
equivClass->superclass = resolvedSuperclass;
// If we have a concrete type, check it.
// FIXME: Substitute into the concrete type.
if (equivClass->concreteType) {
Type resolvedConcreteType =
getCanonicalTypeInContext(equivClass->concreteType, genericParams);
auto existing = equivClass->findAnyConcreteConstraintAsWritten();
// Make sure the concrete type fulfills the superclass requirement.
if (!equivClass->superclass->isExactSuperclassOf(resolvedConcreteType)){
Impl->HadAnyError = true;
if (existing) {
Diags.diagnose(existing->source->getLoc(), diag::type_does_not_inherit,
existing->getSubjectDependentType(getGenericParams()),
existing->value, equivClass->superclass);
if (representativeConstraint.source->getLoc().isValid()) {
Diags.diagnose(representativeConstraint.source->getLoc(),
diag::superclass_redundancy_here,
representativeConstraint.source->classifyDiagKind(),
representativeConstraint.getSubjectDependentType(
genericParams),
equivClass->superclass);
}
} else if (representativeConstraint.source->getLoc().isValid()) {
Diags.diagnose(representativeConstraint.source->getLoc(),
diag::type_does_not_inherit,
representativeConstraint.getSubjectDependentType(
genericParams),
resolvedConcreteType, equivClass->superclass);
}
} else if (representativeConstraint.source->shouldDiagnoseRedundancy(true)
&& existing &&
existing->source->shouldDiagnoseRedundancy(false)) {
// It does fulfill the requirement; diagnose the redundancy.
Diags.diagnose(representativeConstraint.source->getLoc(),
diag::redundant_superclass_constraint,
representativeConstraint.getSubjectDependentType(
genericParams),
representativeConstraint.value);
Diags.diagnose(existing->source->getLoc(),
diag::same_type_redundancy_here,
existing->source->classifyDiagKind(),
existing->getSubjectDependentType(genericParams),
existing->value);
}
}
}
void GenericSignatureBuilder::checkLayoutConstraints(
TypeArrayView<GenericTypeParamType> genericParams,
EquivalenceClass *equivClass) {
if (!equivClass->layout) return;
checkConstraintList<LayoutConstraint>(
genericParams, equivClass->layoutConstraints, RequirementKind::Layout,
[&](const Constraint<LayoutConstraint> &constraint) {
return constraint.value == equivClass->layout;
},
[&](const Constraint<LayoutConstraint> &constraint) {
auto layout = constraint.value;
// If the layout constraints are mergable, i.e. compatible,
// it is a redundancy.
if (layout.merge(equivClass->layout)->isKnownLayout())
return ConstraintRelation::Redundant;
return ConstraintRelation::Conflicting;
},
diag::conflicting_layout_constraints,
diag::redundant_layout_constraint,
diag::previous_layout_constraint);
}
bool GenericSignatureBuilder::isRedundantExplicitRequirement(
ExplicitRequirement req) const {
assert(Impl->computedRedundantRequirements &&
"Must ensure computeRedundantRequirements() is called first");
auto &redundantReqs = Impl->RedundantRequirements;
return (redundantReqs.find(req) != redundantReqs.end());
}
namespace {
template<typename T>
bool hasNonRedundantRequirementSource(ArrayRef<Constraint<T>> constraints,
RequirementKind kind,
GenericSignatureBuilder &builder) {
for (auto constraint : constraints) {
if (constraint.source->isDerivedRequirement())
continue;
auto req = ExplicitRequirement::fromExplicitConstraint(kind, constraint);
if (builder.isRedundantExplicitRequirement(req))
continue;
return true;
}
return false;
}
using SameTypeComponentRef = std::pair<EquivalenceClass *, unsigned>;
} // end anonymous namespace
void GenericSignatureBuilder::enumerateRequirements(
TypeArrayView<GenericTypeParamType> genericParams,
SmallVectorImpl<Requirement> &requirements) {
auto recordRequirement = [&](RequirementKind kind,
Type depTy,
RequirementRHS rhs) {
depTy = getSugaredDependentType(depTy, genericParams);
if (auto type = rhs.dyn_cast<Type>()) {
if (type->hasError())
return;
// Drop requirements involving concrete types containing
// unresolved associated types.
if (type->findUnresolvedDependentMemberType()) {
assert(Impl->HadAnyError);
return;
}
if (type->isTypeParameter())
type = getSugaredDependentType(type, genericParams);
requirements.push_back(Requirement(kind, depTy, type));
} else if (auto *proto = rhs.dyn_cast<ProtocolDecl *>()) {
auto type = proto->getDeclaredInterfaceType();
requirements.push_back(Requirement(kind, depTy, type));
} else {
auto layoutConstraint = rhs.get<LayoutConstraint>();
requirements.push_back(Requirement(kind, depTy, layoutConstraint));
return;
}
};
// Collect all of the subject types that will be involved in constraints.
SmallVector<SameTypeComponentRef, 8> subjects;
for (auto &equivClass : Impl->EquivalenceClasses) {
if (equivClass.derivedSameTypeComponents.empty()) {
checkSameTypeConstraints(getGenericParams(), &equivClass);
}
for (unsigned i : indices(equivClass.derivedSameTypeComponents))
subjects.push_back({&equivClass, i});
}
for (const auto &subject : subjects) {
// Dig out the subject type and its corresponding component.
auto equivClass = subject.first;
auto &component = equivClass->derivedSameTypeComponents[subject.second];
Type subjectType = component.type;
assert(!subjectType->hasError());
assert(!subjectType->findUnresolvedDependentMemberType());
// If this equivalence class is bound to a concrete type, equate the
// anchor with a concrete type.
if (Type concreteType = equivClass->concreteType) {
// If the parent of this anchor is also a concrete type, don't
// create a requirement.
if (!subjectType->is<GenericTypeParamType>() &&
maybeResolveEquivalenceClass(
subjectType->castTo<DependentMemberType>()->getBase(),
ArchetypeResolutionKind::WellFormed,
/*wantExactPotentialArchetype=*/false)
.getEquivalenceClass(*this)->concreteType)
continue;
// Drop recursive and invalid concrete-type constraints.
if (equivClass->recursiveConcreteType ||
equivClass->invalidConcreteType)
continue;
// Filter out derived requirements... except for concrete-type
// requirements on generic parameters. The exception is due to
// the canonicalization of generic signatures, which never
// eliminates generic parameters even when they have been
// mapped to a concrete type.
if (subjectType->is<GenericTypeParamType>() ||
component.concreteTypeSource == nullptr ||
!component.concreteTypeSource->isDerivedRequirement()) {
recordRequirement(RequirementKind::SameType,
subjectType, concreteType);
}
continue;
}
std::function<void()> deferredSameTypeRequirement;
// If we're at the last anchor in the component, do nothing;
if (subject.second + 1 != equivClass->derivedSameTypeComponents.size()) {
// Form a same-type constraint from this anchor within the component
// to the next.
// FIXME: Distinguish between explicit and inferred here?
auto &nextComponent =
equivClass->derivedSameTypeComponents[subject.second + 1];
Type otherSubjectType = nextComponent.type;
deferredSameTypeRequirement =
[&recordRequirement, subjectType, otherSubjectType] {
recordRequirement(RequirementKind::SameType,
subjectType, otherSubjectType);
};
}
SWIFT_DEFER {
if (deferredSameTypeRequirement) deferredSameTypeRequirement();
};
// If this is not the first component anchor in its equivalence class,
// we're done.
if (subject.second > 0)
continue;
// If we have a superclass, produce a superclass requirement
if (equivClass->superclass &&
!equivClass->recursiveSuperclassType &&
!equivClass->superclass->hasError()) {
if (hasNonRedundantRequirementSource<Type>(
equivClass->superclassConstraints,
RequirementKind::Superclass, *this)) {
recordRequirement(RequirementKind::Superclass,
subjectType, equivClass->superclass);
}
}
// If we have a layout constraint, produce a layout requirement.
if (equivClass->layout) {
if (hasNonRedundantRequirementSource<LayoutConstraint>(
equivClass->layoutConstraints,
RequirementKind::Layout, *this)) {
recordRequirement(RequirementKind::Layout,
subjectType, equivClass->layout);
}
}
// Enumerate conformance requirements.
SmallVector<ProtocolDecl *, 4> protocols;
for (const auto &conforms : equivClass->conformsTo) {
if (hasNonRedundantRequirementSource<ProtocolDecl *>(
conforms.second, RequirementKind::Conformance, *this)) {
protocols.push_back(conforms.first);
}
}
// Sort the protocols in canonical order.
llvm::array_pod_sort(protocols.begin(), protocols.end(),
TypeDecl::compare);
// Enumerate the conformance requirements.
for (auto proto : protocols) {
recordRequirement(RequirementKind::Conformance, subjectType, proto);
}
}
// Sort the subject types in canonical order. This needs to be a stable sort
// so that the relative order of requirements that have the same subject type
// is preserved.
std::stable_sort(requirements.begin(), requirements.end(),
[](const Requirement &lhs, const Requirement &rhs) {
return compareDependentTypes(lhs.getFirstType(),
rhs.getFirstType()) < 0;
});
}
void GenericSignatureBuilder::dump() {
dump(llvm::errs());
}
void GenericSignatureBuilder::dump(llvm::raw_ostream &out) {
out << "Potential archetypes:\n";
for (auto pa : Impl->PotentialArchetypes) {
pa->dump(out, &Context.SourceMgr, 2);
}
out << "\n";
out << "Equivalence classes:\n";
for (auto &equiv : Impl->EquivalenceClasses) {
equiv.dump(out, this);
}
out << "\n";
}
void GenericSignatureBuilder::addGenericSignature(GenericSignature sig) {
if (!sig) return;
for (auto param : sig->getGenericParams())
addGenericParameter(param);
for (auto &reqt : sig->getRequirements())
addRequirement(reqt, FloatingRequirementSource::forAbstract(), nullptr);
}
#ifndef NDEBUG
/// Determine the canonical ordering of requirements.
static unsigned getRequirementKindOrder(RequirementKind kind) {
switch (kind) {
case RequirementKind::Conformance: return 2;
case RequirementKind::Superclass: return 0;
case RequirementKind::SameType: return 3;
case RequirementKind::Layout: return 1;
}
llvm_unreachable("unhandled kind");
}
static void checkGenericSignature(CanGenericSignature canSig,
GenericSignatureBuilder &builder) {
PrettyStackTraceGenericSignature debugStack("checking", canSig);
auto canonicalRequirements = canSig->getRequirements();
// Check that the signature is canonical.
for (unsigned idx : indices(canonicalRequirements)) {
debugStack.setRequirement(idx);
const auto &reqt = canonicalRequirements[idx];
// Left-hand side must be canonical in its context.
// Check canonicalization of requirement itself.
switch (reqt.getKind()) {
case RequirementKind::Superclass:
assert(canSig->isCanonicalTypeInContext(reqt.getFirstType(), builder) &&
"Left-hand side is not canonical");
assert(canSig->isCanonicalTypeInContext(reqt.getSecondType(), builder) &&
"Superclass type isn't canonical in its own context");
break;
case RequirementKind::Layout:
assert(canSig->isCanonicalTypeInContext(reqt.getFirstType(), builder) &&
"Left-hand side is not canonical");
break;
case RequirementKind::SameType: {
auto isCanonicalAnchor = [&](Type type) {
if (auto *dmt = type->getAs<DependentMemberType>())
return canSig->isCanonicalTypeInContext(dmt->getBase(), builder);
return type->is<GenericTypeParamType>();
};
auto firstType = reqt.getFirstType();
auto secondType = reqt.getSecondType();
assert(isCanonicalAnchor(firstType));
if (reqt.getSecondType()->isTypeParameter()) {
assert(isCanonicalAnchor(secondType));
assert(compareDependentTypes(firstType, secondType) < 0 &&
"Out-of-order type parameters in same-type constraint");
} else {
assert(canSig->isCanonicalTypeInContext(secondType) &&
"Concrete same-type isn't canonical in its own context");
}
break;
}
case RequirementKind::Conformance:
assert(canSig->isCanonicalTypeInContext(reqt.getFirstType(), builder) &&
"Left-hand side is not canonical");
assert(reqt.getFirstType()->isTypeParameter() &&
"Left-hand side must be a type parameter");
assert(isa<ProtocolType>(reqt.getSecondType().getPointer()) &&
"Right-hand side of conformance isn't a protocol type");
break;
}
// From here on, we're only interested in requirements beyond the first.
if (idx == 0) continue;
// Make sure that the left-hand sides are in nondecreasing order.
const auto &prevReqt = canonicalRequirements[idx-1];
int compareLHS =
compareDependentTypes(prevReqt.getFirstType(), reqt.getFirstType());
assert(compareLHS <= 0 && "Out-of-order left-hand sides");
// If we have two same-type requirements where the left-hand sides differ
// but fall into the same equivalence class, we can check the form.
if (compareLHS < 0 && reqt.getKind() == RequirementKind::SameType &&
prevReqt.getKind() == RequirementKind::SameType &&
canSig->areSameTypeParameterInContext(prevReqt.getFirstType(),
reqt.getFirstType(),
builder)) {
// If it's a it's a type parameter, make sure the equivalence class is
// wired together sanely.
if (prevReqt.getSecondType()->isTypeParameter()) {
assert(prevReqt.getSecondType()->isEqual(reqt.getFirstType()) &&
"same-type constraints within an equiv. class are out-of-order");
} else {
// Otherwise, the concrete types must match up.
assert(prevReqt.getSecondType()->isEqual(reqt.getSecondType()) &&
"inconsistent concrete same-type constraints in equiv. class");
}
}
// From here on, we only care about cases where the previous and current
// requirements have the same left-hand side.
if (compareLHS != 0) continue;
// Check ordering of requirement kinds.
assert((getRequirementKindOrder(prevReqt.getKind()) <=
getRequirementKindOrder(reqt.getKind())) &&
"Requirements for a given kind are out-of-order");
// From here on, we only care about the same requirement kind.
if (prevReqt.getKind() != reqt.getKind()) continue;
assert(reqt.getKind() == RequirementKind::Conformance &&
"Only conformance requirements can have multiples");
auto prevProto = prevReqt.getProtocolDecl();
auto proto = reqt.getProtocolDecl();
assert(TypeDecl::compare(prevProto, proto) < 0 &&
"Out-of-order conformance requirements");
}
}
#endif
bool GenericSignatureBuilder::hasExplicitConformancesImpliedByConcrete() const {
for (auto pair : Impl->RedundantRequirements) {
if (pair.first.getKind() != RequirementKind::Conformance)
continue;
for (auto impliedByReq : pair.second) {
if (impliedByReq.getKind() == RequirementKind::Superclass)
return true;
if (impliedByReq.getKind() == RequirementKind::SameType)
return true;
}
}
return false;
}
static Type stripBoundDependentMemberTypes(Type t) {
if (auto *depMemTy = t->getAs<DependentMemberType>()) {
return DependentMemberType::get(
stripBoundDependentMemberTypes(depMemTy->getBase()),
depMemTy->getName());
}
return t;
}
static Requirement stripBoundDependentMemberTypes(Requirement req) {
auto subjectType = stripBoundDependentMemberTypes(req.getFirstType());
switch (req.getKind()) {
case RequirementKind::Conformance:
return Requirement(RequirementKind::Conformance, subjectType,
req.getSecondType());
case RequirementKind::Superclass:
case RequirementKind::SameType:
return Requirement(req.getKind(), subjectType,
req.getSecondType().transform([](Type t) {
return stripBoundDependentMemberTypes(t);
}));
case RequirementKind::Layout:
return Requirement(RequirementKind::Conformance, subjectType,
req.getLayoutConstraint());
}
llvm_unreachable("Bad requirement kind");
}
GenericSignature GenericSignatureBuilder::computeGenericSignature(
bool allowConcreteGenericParams,
bool buildingRequirementSignature,
bool rebuildingWithoutRedundantConformances) && {
// Finalize the builder, producing any necessary diagnostics.
finalize(getGenericParams(), allowConcreteGenericParams);
// Collect the requirements placed on the generic parameter types.
SmallVector<Requirement, 4> requirements;
enumerateRequirements(getGenericParams(), requirements);
// Form the generic signature.
auto sig = GenericSignature::get(getGenericParams(), requirements);
// If any of our explicit conformance requirements were implied by
// superclass or concrete same-type requirements, we have to build the
// signature again, since dropping the redundant conformance requirements
// changes the canonical type computation.
//
// However, if we already diagnosed an error, don't do this, because
// we might end up emitting duplicate diagnostics.
//
// Also, don't do this when building a requirement signature.
if (!buildingRequirementSignature &&
!Impl->HadAnyError &&
hasExplicitConformancesImpliedByConcrete()) {
NumSignaturesRebuiltWithoutRedundantRequirements++;
if (rebuildingWithoutRedundantConformances) {
llvm::errs() << "Rebuilt signature still has "
<< "redundant conformance requirements: ";
llvm::errs() << sig << "\n";
abort();
}
GenericSignatureBuilder newBuilder(Context);
for (auto param : sig->getGenericParams())
newBuilder.addGenericParameter(param);
for (auto &req : sig->getRequirements()) {
newBuilder.addRequirement(stripBoundDependentMemberTypes(req),
FloatingRequirementSource::forAbstract(), nullptr);
}
return std::move(newBuilder).computeGenericSignature(
allowConcreteGenericParams,
buildingRequirementSignature,
/*rebuildingWithoutRedundantConformances=*/true);
}
#ifndef NDEBUG
if (!Impl->HadAnyError) {
checkGenericSignature(sig.getCanonicalSignature(), *this);
}
#endif
// When we can, move this generic signature builder to make it the canonical
// builder, rather than constructing a new generic signature builder that
// will produce the same thing.
//
// We cannot do this when there were errors.
//
// Also, we cannot do this when building a requirement signature.
if (!buildingRequirementSignature && !Impl->HadAnyError) {
// Register this generic signature builder as the canonical builder for the
// given signature.
Context.registerGenericSignatureBuilder(sig, std::move(*this));
}
// Wipe out the internal state, ensuring that nobody uses this builder for
// anything more.
Impl.reset();
return sig;
}
#pragma mark Generic signature verification
void GenericSignatureBuilder::verifyGenericSignature(ASTContext &context,
GenericSignature sig) {
llvm::errs() << "Validating generic signature: ";
sig->print(llvm::errs());
llvm::errs() << "\n";
// Try building a new signature having the same requirements.
auto genericParams = sig->getGenericParams();
auto requirements = sig->getRequirements();
{
PrettyStackTraceGenericSignature debugStack("verifying", sig);
// Form a new generic signature builder.
GenericSignatureBuilder builder(context);
// Add the generic parameters.
for (auto gp : genericParams)
builder.addGenericParameter(gp);
// Add the requirements.
auto source = FloatingRequirementSource::forAbstract();
for (auto req : requirements)
builder.addRequirement(req, source, nullptr);
// If there were any errors, the signature was invalid.
if (builder.Impl->HadAnyError) {
context.Diags.diagnose(SourceLoc(), diag::generic_signature_not_valid,
sig->getAsString());
}
// Form a generic signature from the result.
auto newSig =
std::move(builder).computeGenericSignature(
/*allowConcreteGenericParams=*/true);
// The new signature should be equal.
if (!newSig->isEqual(sig)) {
context.Diags.diagnose(SourceLoc(), diag::generic_signature_not_equal,
sig->getAsString(), newSig->getAsString());
}
}
// Try removing each requirement in turn.
for (unsigned victimIndex : indices(requirements)) {
PrettyStackTraceGenericSignature debugStack("verifying", sig, victimIndex);
// Form a new generic signature builder.
GenericSignatureBuilder builder(context);
// Add the generic parameters.
for (auto gp : genericParams)
builder.addGenericParameter(gp);
// Add the requirements *except* the victim.
auto source = FloatingRequirementSource::forAbstract();
for (unsigned i : indices(requirements)) {
if (i != victimIndex)
builder.addRequirement(requirements[i], source, nullptr);
}
// If there were any errors, we formed an invalid signature, so
// just continue.
if (builder.Impl->HadAnyError) continue;
// Form a generic signature from the result.
auto newSig =
std::move(builder).computeGenericSignature(
/*allowConcreteGenericParams=*/true);
// If the removed requirement is satisfied by the new generic signature,
// it is redundant. Complain.
if (newSig->isRequirementSatisfied(requirements[victimIndex])) {
SmallString<32> reqString;
{
llvm::raw_svector_ostream out(reqString);
requirements[victimIndex].print(out, PrintOptions());
}
context.Diags.diagnose(SourceLoc(), diag::generic_signature_not_minimal,
reqString, sig->getAsString());
}
// Canonicalize the signature to check that it is canonical.
(void)newSig.getCanonicalSignature();
}
}
void GenericSignatureBuilder::verifyGenericSignaturesInModule(
ModuleDecl *module) {
LoadedFile *loadedFile = nullptr;
for (auto fileUnit : module->getFiles()) {
loadedFile = dyn_cast<LoadedFile>(fileUnit);
if (loadedFile) break;
}
if (!loadedFile) return;
// Check all of the (canonical) generic signatures.
SmallVector<GenericSignature, 8> allGenericSignatures;
SmallPtrSet<CanGenericSignature, 4> knownGenericSignatures;
(void)loadedFile->getAllGenericSignatures(allGenericSignatures);
ASTContext &context = module->getASTContext();
for (auto genericSig : allGenericSignatures) {
// Check whether this is the first time we've checked this (canonical)
// signature.
auto canGenericSig = genericSig.getCanonicalSignature();
if (!knownGenericSignatures.insert(canGenericSig).second) continue;
verifyGenericSignature(context, canGenericSig);
}
}
bool AbstractGenericSignatureRequest::isCached() const {
return true;
}
bool InferredGenericSignatureRequest::isCached() const {
return true;
}
/// Check whether the inputs to the \c AbstractGenericSignatureRequest are
/// all canonical.
static bool isCanonicalRequest(GenericSignature baseSignature,
ArrayRef<GenericTypeParamType *> genericParams,
ArrayRef<Requirement> requirements) {
if (baseSignature && !baseSignature->isCanonical())
return false;
for (auto gp : genericParams) {
if (!gp->isCanonical())
return false;
}
for (const auto &req : requirements) {
if (!req.isCanonical())
return false;
}
return true;
}
GenericSignature
AbstractGenericSignatureRequest::evaluate(
Evaluator &evaluator,
const GenericSignatureImpl *baseSignature,
SmallVector<GenericTypeParamType *, 2> addedParameters,
SmallVector<Requirement, 2> addedRequirements) const {
// If nothing is added to the base signature, just return the base
// signature.
if (addedParameters.empty() && addedRequirements.empty())
return baseSignature;
ASTContext &ctx = addedParameters.empty()
? addedRequirements.front().getFirstType()->getASTContext()
: addedParameters.front()->getASTContext();
// If there are no added requirements, we can form the signature directly
// with the added parameters.
if (addedRequirements.empty()) {
ArrayRef<Requirement> requirements;
if (baseSignature) {
addedParameters.insert(addedParameters.begin(),
baseSignature->getGenericParams().begin(),
baseSignature->getGenericParams().end());
requirements = baseSignature->getRequirements();
}
return GenericSignature::get(addedParameters, requirements);
}
// If the request is non-canonical, we won't need to build our own
// generic signature builder.
if (!isCanonicalRequest(baseSignature, addedParameters, addedRequirements)) {
// Canonicalize the inputs so we can form the canonical request.
GenericSignature canBaseSignature;
if (baseSignature)
canBaseSignature = baseSignature->getCanonicalSignature();
SmallVector<GenericTypeParamType *, 2> canAddedParameters;
canAddedParameters.reserve(addedParameters.size());
for (auto gp : addedParameters) {
auto canGP = gp->getCanonicalType()->castTo<GenericTypeParamType>();
canAddedParameters.push_back(canGP);
}
SmallVector<Requirement, 2> canAddedRequirements;
canAddedRequirements.reserve(addedRequirements.size());
for (const auto &req : addedRequirements) {
canAddedRequirements.push_back(req.getCanonical());
}
// Build the canonical signature.
auto canSignatureResult = evaluator(
AbstractGenericSignatureRequest{
canBaseSignature.getPointer(), std::move(canAddedParameters),
std::move(canAddedRequirements)});
if (!canSignatureResult || !*canSignatureResult)
return GenericSignature();
// Substitute in the original generic parameters to form the sugared
// result the original request wanted.
auto canSignature = *canSignatureResult;
SmallVector<GenericTypeParamType *, 2> resugaredParameters;
resugaredParameters.reserve(canSignature->getGenericParams().size());
if (baseSignature) {
resugaredParameters.append(baseSignature->getGenericParams().begin(),
baseSignature->getGenericParams().end());
}
resugaredParameters.append(addedParameters.begin(), addedParameters.end());
assert(resugaredParameters.size() ==
canSignature->getGenericParams().size());
SmallVector<Requirement, 2> resugaredRequirements;
resugaredRequirements.reserve(canSignature->getRequirements().size());
for (const auto &req : canSignature->getRequirements()) {
auto resugaredReq = req.subst(
[&](SubstitutableType *type) {
if (auto gp = dyn_cast<GenericTypeParamType>(type)) {
unsigned ordinal = canSignature->getGenericParamOrdinal(gp);
return Type(resugaredParameters[ordinal]);
}
return Type(type);
},
MakeAbstractConformanceForGenericType(),
SubstFlags::AllowLoweredTypes);
resugaredRequirements.push_back(*resugaredReq);
}
return GenericSignature::get(resugaredParameters, resugaredRequirements);
}
// Create a generic signature that will form the signature.
GenericSignatureBuilder builder(ctx);
if (baseSignature)
builder.addGenericSignature(baseSignature);
auto source =
GenericSignatureBuilder::FloatingRequirementSource::forAbstract();
for (auto param : addedParameters)
builder.addGenericParameter(param);
for (const auto &req : addedRequirements)
builder.addRequirement(req, source, nullptr);
return std::move(builder).computeGenericSignature(
/*allowConcreteGenericParams=*/true);
}
GenericSignature
InferredGenericSignatureRequest::evaluate(
Evaluator &evaluator, ModuleDecl *parentModule,
const GenericSignatureImpl *parentSig,
GenericParamSource paramSource,
SmallVector<Requirement, 2> addedRequirements,
SmallVector<TypeLoc, 2> inferenceSources,
bool allowConcreteGenericParams) const {
GenericSignatureBuilder builder(parentModule->getASTContext());
// If there is a parent context, add the generic parameters and requirements
// from that context.
builder.addGenericSignature(parentSig);
DeclContext *lookupDC = nullptr;
const auto visitRequirement = [&](const Requirement &req,
RequirementRepr *reqRepr) {
const auto source = FloatingRequirementSource::forExplicit(reqRepr);
// If we're extending a protocol and adding a redundant requirement,
// for example, `extension Foo where Self: Foo`, then emit a
// diagnostic.
if (auto decl = lookupDC->getAsDecl()) {
if (auto extDecl = dyn_cast<ExtensionDecl>(decl)) {
auto extType = extDecl->getDeclaredInterfaceType();
auto extSelfType = extDecl->getSelfInterfaceType();
auto reqLHSType = req.getFirstType();
auto reqRHSType = req.getSecondType();
if (extType->isExistentialType() &&
reqLHSType->isEqual(extSelfType) &&
reqRHSType->isEqual(extType)) {
auto &ctx = extDecl->getASTContext();
ctx.Diags.diagnose(extDecl->getLoc(),
diag::protocol_extension_redundant_requirement,
extType->getString(),
extSelfType->getString(),
reqRHSType->getString());
}
}
}
builder.addRequirement(req, reqRepr, source, nullptr,
lookupDC->getParentModule());
return false;
};
GenericParamList *genericParams = nullptr;
if (auto params = paramSource.dyn_cast<GenericParamList *>())
genericParams = params;
else
genericParams = paramSource.get<GenericContext *>()->getGenericParams();
if (genericParams) {
// Extensions never have a parent signature.
if (genericParams->getOuterParameters())
assert(parentSig == nullptr);
// Type check the generic parameters, treating all generic type
// parameters as dependent, unresolved.
SmallVector<GenericParamList *, 2> gpLists;
for (auto *outerParams = genericParams;
outerParams != nullptr;
outerParams = outerParams->getOuterParameters()) {
gpLists.push_back(outerParams);
}
// The generic parameter lists MUST appear from innermost to outermost.
// We walk them backwards to order outer requirements before
// inner requirements.
for (auto &genericParams : llvm::reverse(gpLists)) {
assert(genericParams->size() > 0 &&
"Parsed an empty generic parameter list?");
// First, add the generic parameters to the generic signature builder.
// Do this before checking the inheritance clause, since it may
// itself be dependent on one of these parameters.
for (const auto param : *genericParams)
builder.addGenericParameter(param);
// Add the requirements for each of the generic parameters to the builder.
// Now, check the inheritance clauses of each parameter.
for (const auto param : *genericParams)
builder.addGenericParameterRequirements(param);
// Determine where and how to perform name lookup.
lookupDC = genericParams->begin()[0]->getDeclContext();
// Add the requirements clause to the builder.
WhereClauseOwner(lookupDC, genericParams)
.visitRequirements(TypeResolutionStage::Structural,
visitRequirement);
}
}
if (auto *ctx = paramSource.dyn_cast<GenericContext *>()) {
// The declaration might have a trailing where clause.
if (auto *where = ctx->getTrailingWhereClause()) {
// Determine where and how to perform name lookup.
lookupDC = ctx;
WhereClauseOwner(lookupDC, where).visitRequirements(
TypeResolutionStage::Structural, visitRequirement);
}
}
/// Perform any remaining requirement inference.
for (auto sourcePair : inferenceSources) {
auto source =
FloatingRequirementSource::forInferred(sourcePair.getTypeRepr());
builder.inferRequirements(*parentModule,
sourcePair.getType(),
source);
}
// Finish by adding any remaining requirements.
auto source =
FloatingRequirementSource::forInferred(nullptr);
for (const auto &req : addedRequirements)
builder.addRequirement(req, source, parentModule);
return std::move(builder).computeGenericSignature(
allowConcreteGenericParams);
}