Merge pull request #11751 from DougGregor/gsb-nested-same-type-match
diff --git a/include/swift/AST/GenericSignatureBuilder.h b/include/swift/AST/GenericSignatureBuilder.h
index 0b42263..ddf8ebe 100644
--- a/include/swift/AST/GenericSignatureBuilder.h
+++ b/include/swift/AST/GenericSignatureBuilder.h
@@ -317,6 +317,15 @@
const RequirementSource *Source);
public:
+ /// "Expand" the conformance of the given \c pa to the protocol \c proto,
+ /// adding the requirements from its requirement signature, rooted at
+ /// the given requirement \c source.
+ ConstraintResult expandConformanceRequirement(
+ PotentialArchetype *pa,
+ ProtocolDecl *proto,
+ const RequirementSource *source,
+ bool onlySameTypeConstraints);
+
/// \brief Add a new same-type requirement between two fully resolved types
/// (output of \c GenericSignatureBuilder::resolve).
///
@@ -824,6 +833,11 @@
/// A requirement that was resolved based on structural derivation from
/// another requirement.
Derived,
+
+ /// A requirement that was provided for another potential archetype in the
+ /// same equivalence class, but which we want to "re-root" on a new
+ /// potential archetype.
+ EquivalentType,
};
/// The kind of requirement source.
@@ -882,6 +896,7 @@
case Parent:
case Concrete:
case Derived:
+ case EquivalentType:
return 0;
}
@@ -927,6 +942,7 @@
case Parent:
case Concrete:
case Derived:
+ case EquivalentType:
return false;
}
@@ -1011,6 +1027,18 @@
"RequirementSource kind/storageKind mismatch");
}
+ RequirementSource(Kind kind, const RequirementSource *parent,
+ PotentialArchetype *newPA)
+ : kind(kind), storageKind(StorageKind::RootArchetype),
+ hasTrailingWrittenRequirementLoc(false),
+ usesRequirementSignature(false), parent(parent) {
+ assert((static_cast<bool>(parent) != isRootKind(kind)) &&
+ "Root RequirementSource should not have parent (or vice versa)");
+ assert(isAcceptableStorageKind(kind, storageKind) &&
+ "RequirementSource kind/storageKind mismatch");
+ storage.rootArchetype = newPA;
+ }
+
public:
/// Retrieve an abstract requirement source.
static const RequirementSource *forAbstract(PotentialArchetype *root);
@@ -1076,6 +1104,11 @@
/// derived from another constraint but does not require further information.
const RequirementSource *viaDerived(GenericSignatureBuilder &builder) const;
+ /// A constraint source that describes a constraint that is structurally
+ /// derived from another constraint but does not require further information.
+ const RequirementSource *viaEquivalentType(GenericSignatureBuilder &builder,
+ PotentialArchetype *newPA) const;
+
/// Form a new requirement source without the subpath [start, end).
///
/// Removes a redundant sub-path \c [start, end) from the requirement source,
@@ -1427,10 +1460,12 @@
{
}
+public:
/// \brief Retrieve the representative for this archetype, performing
/// path compression on the way.
PotentialArchetype *getRepresentative() const;
+private:
/// Retrieve the generic signature builder with which this archetype is
/// associated.
GenericSignatureBuilder *getBuilder() const {
@@ -1695,6 +1730,12 @@
UnresolvedType lhs;
RequirementRHS rhs;
FloatingRequirementSource source;
+
+ /// Dump a debugging representation of this delayed requirement class.
+ void dump(llvm::raw_ostream &out) const;
+
+ LLVM_ATTRIBUTE_DEPRECATED(void dump() const,
+ "only for use in the debugger");
};
/// Whether the given constraint result signals an error.
diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp
index 19f11ec..b29b4db 100644
--- a/lib/AST/GenericSignatureBuilder.cpp
+++ b/lib/AST/GenericSignatureBuilder.cpp
@@ -58,6 +58,7 @@
GenericSignatureBuilder::Constraint<T>;
typedef GenericSignatureBuilder::EquivalenceClass EquivalenceClass;
typedef EquivalenceClass::DerivedSameTypeComponent DerivedSameTypeComponent;
+ typedef GenericSignatureBuilder::DelayedRequirement DelayedRequirement;
} // end anonymous namespace
@@ -343,6 +344,7 @@
case RequirementSignatureSelf:
case NestedTypeNameMatch:
case ConcreteTypeBinding:
+ case EquivalentType:
switch (storageKind) {
case StorageKind::RootArchetype:
return true;
@@ -455,14 +457,15 @@
return true;
case QuietlyInferred:
+ case NestedTypeNameMatch:
return includeQuietInferred;
case ConcreteTypeBinding:
+ case EquivalentType:
return false;
case Concrete:
case Explicit:
- case NestedTypeNameMatch:
case Parent:
case ProtocolRequirement:
case RequirementSignatureSelf:
@@ -495,6 +498,7 @@
case Concrete:
case RequirementSignatureSelf:
case Derived:
+ case EquivalentType:
return true;
case ProtocolRequirement:
@@ -638,7 +642,9 @@
case Concrete:
case Superclass:
case Derived:
+ case EquivalentType:
return false;
+
case Explicit:
case Inferred:
case QuietlyInferred:
@@ -832,6 +838,15 @@
0, WrittenRequirementLoc());
}
+const RequirementSource *RequirementSource::viaEquivalentType(
+ GenericSignatureBuilder &builder,
+ PotentialArchetype *newPA) const {
+ REQUIREMENT_SOURCE_FACTORY_BODY(
+ (nodeID, EquivalentType, this, newPA, nullptr, nullptr),
+ (EquivalentType, this, newPA),
+ 0, WrittenRequirementLoc());
+}
+
#undef REQUIREMENT_SOURCE_FACTORY_BODY
const RequirementSource *RequirementSource::withoutRedundantSubpath(
@@ -884,6 +899,10 @@
return parent->withoutRedundantSubpath(start, end)
->viaDerived(builder);
+ case EquivalentType:
+ return parent->withoutRedundantSubpath(start, end)
+ ->viaEquivalentType(builder, getAffectedPotentialArchetype());
+
case Parent:
return parent->withoutRedundantSubpath(start, end)
->viaParent(builder, getAssociatedType());
@@ -950,6 +969,15 @@
case RequirementSource::Derived:
return parent->visitPotentialArchetypesAlongPath(visitor);
+ case RequirementSource::EquivalentType: {
+ auto parentPA = parent->visitPotentialArchetypesAlongPath(visitor);
+ if (!parentPA) return nullptr;
+
+ if (visitor(parentPA, this)) return nullptr;
+
+ return storage.rootArchetype;
+ }
+
case RequirementSource::ProtocolRequirement:
case RequirementSource::InferredProtocolRequirement: {
auto parentPA = parent->visitPotentialArchetypesAlongPath(visitor);
@@ -1139,6 +1167,10 @@
case Derived:
out << "Derived";
break;
+
+ case EquivalentType:
+ out << "Equivalent type";
+ break;
}
// Local function to dump a source location, if we can.
@@ -1299,6 +1331,7 @@
case RequirementSource::InferredProtocolRequirement:
case RequirementSource::Superclass:
case RequirementSource::Derived:
+ case RequirementSource::EquivalentType:
return false;
}
@@ -1321,6 +1354,7 @@
case RequirementSource::Parent:
case RequirementSource::Superclass:
case RequirementSource::Derived:
+ case RequirementSource::EquivalentType:
return false;
}
}
@@ -1352,6 +1386,10 @@
llvm::SmallSet<std::pair<CanType, ProtocolDecl *>, 4> 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;
@@ -1510,6 +1548,14 @@
if (layout)
out << "\nLayout: " << layout.getString();
+ if (!delayedRequirements.empty()) {
+ out << "\nDelayed requirements:";
+ for (const auto &req : delayedRequirements) {
+ out << "\n ";
+ req.dump(out);
+ }
+ }
+
out << "\n";
{
@@ -1548,6 +1594,38 @@
dump(llvm::errs());
}
+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,
@@ -2811,7 +2889,7 @@
// fails, it's because we weren't allowed to resolve anything now.
auto resolved = resolvePotentialArchetype(type, resolutionKind);
pa = resolved.dyn_cast<PotentialArchetype *>();
- if (!pa) return resolved.get<EquivalenceClass *>();
+ if (!pa) return resolved.get<EquivalenceClass *>();
}
return ResolvedType::forPotentialArchetype(pa);
@@ -2886,26 +2964,27 @@
return result;
}
-ConstraintResult GenericSignatureBuilder::addConformanceRequirement(
- PotentialArchetype *PAT,
- ProtocolDecl *Proto,
- const RequirementSource *Source) {
- // Add the requirement, if we haven't done so already.
- if (!PAT->addConformance(Proto, Source, *this))
- return ConstraintResult::Resolved;
-
- auto concreteSelf = PAT->getDependentType({});
+ConstraintResult GenericSignatureBuilder::expandConformanceRequirement(
+ PotentialArchetype *pa,
+ ProtocolDecl *proto,
+ const RequirementSource *source,
+ bool onlySameTypeConstraints) {
+ auto concreteSelf = pa->getDependentType({});
auto protocolSubMap = SubstitutionMap::getProtocolSubstitutions(
- Proto, concreteSelf, ProtocolConformanceRef(Proto));
+ proto, concreteSelf, 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->isRequirementSignatureComputed()) {
+ if (proto->isRequirementSignatureComputed()) {
auto innerSource =
- FloatingRequirementSource::viaProtocolRequirement(Source, Proto,
+ FloatingRequirementSource::viaProtocolRequirement(source, proto,
/*inferred=*/false);
- for (const auto &req : Proto->getRequirementSignature()) {
+ 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 reqResult = addRequirement(req, innerSource, nullptr,
&protocolSubMap);
if (isErrorResult(reqResult)) return reqResult;
@@ -2914,22 +2993,29 @@
return ConstraintResult::Resolved;
}
- // Add all of the inherited protocol requirements, recursively.
- if (auto resolver = getLazyResolver())
- resolver->resolveInheritedProtocols(Proto);
+ auto protoModule = proto->getParentModule();
- auto protoModule = Proto->getParentModule();
+ if (!onlySameTypeConstraints) {
+ // Add all of the inherited protocol requirements, recursively.
+ if (auto resolver = getLazyResolver())
+ resolver->resolveInheritedProtocols(proto);
- auto inheritedReqResult =
- addInheritedRequirements(Proto, PAT, Source, protoModule);
- if (isErrorResult(inheritedReqResult))
- return inheritedReqResult;
+ auto inheritedReqResult =
+ addInheritedRequirements(proto, pa, source, protoModule);
+ if (isErrorResult(inheritedReqResult))
+ return inheritedReqResult;
+ }
// Add any requirements in the where clause on the protocol.
- if (auto WhereClause = Proto->getTrailingWhereClause()) {
+ if (auto WhereClause = proto->getTrailingWhereClause()) {
for (auto &req : WhereClause->getRequirements()) {
+ // If we're only looking at same-type constraints, skip everything else.
+ if (onlySameTypeConstraints &&
+ req.getKind() != RequirementReprKind::SameType)
+ continue;
+
auto innerSource = FloatingRequirementSource::viaProtocolRequirement(
- Source, Proto, &req, /*inferred=*/false);
+ source, proto, &req, /*inferred=*/false);
addRequirement(&req, innerSource, &protocolSubMap, protoModule);
}
}
@@ -2938,9 +3024,9 @@
// inherited protocols (recursively).
llvm::MapVector<DeclName, TinyPtrVector<TypeDecl *>> inheritedTypeDecls;
{
- Proto->walkInheritedProtocols(
+ proto->walkInheritedProtocols(
[&](ProtocolDecl *inheritedProto) -> TypeWalker::Action {
- if (inheritedProto == Proto) return TypeWalker::Action::Continue;
+ if (inheritedProto == proto) return TypeWalker::Action::Continue;
for (auto req : getProtocolMembers(inheritedProto)) {
if (auto typeReq = dyn_cast<TypeDecl>(req))
@@ -2954,11 +3040,11 @@
// clause, as well as the string to start the insertion ("where" or ",");
auto getProtocolWhereLoc = [&]() -> std::pair<SourceLoc, const char *> {
// Already has a trailing where clause.
- if (auto trailing = Proto->getTrailingWhereClause())
+ if (auto trailing = proto->getTrailingWhereClause())
return { trailing->getRequirements().back().getSourceRange().End, ", " };
// Inheritance clause.
- return { Proto->getInherited().back().getSourceRange().End, " where " };
+ return { proto->getInherited().back().getSourceRange().End, " where " };
};
// Retrieve the set of requirements that a given associated type declaration
@@ -3032,30 +3118,39 @@
auto inferredSameTypeSource =
FloatingRequirementSource::viaProtocolRequirement(
- Source, Proto, WrittenRequirementLoc(), /*inferred=*/true);
+ source, proto, WrittenRequirementLoc(), /*inferred=*/true);
addRequirement(
Requirement(RequirementKind::SameType, firstType, secondType),
- inferredSameTypeSource, Proto->getParentModule(),
+ inferredSameTypeSource, proto->getParentModule(),
&protocolSubMap);
};
// Add requirements for each of the associated types.
- for (auto Member : getProtocolMembers(Proto)) {
+ for (auto Member : getProtocolMembers(proto)) {
if (auto assocTypeDecl = dyn_cast<AssociatedTypeDecl>(Member)) {
// Add requirements placed directly on this associated type.
Type assocType = DependentMemberType::get(concreteSelf, assocTypeDecl);
- auto assocResult =
- addInheritedRequirements(assocTypeDecl, assocType, Source, protoModule);
- if (isErrorResult(assocResult))
- return assocResult;
+ if (!onlySameTypeConstraints) {
+ auto assocResult =
+ addInheritedRequirements(assocTypeDecl, assocType, source,
+ protoModule);
+ if (isErrorResult(assocResult))
+ return assocResult;
+ }
// Add requirements from this associated type's where clause.
if (auto WhereClause = assocTypeDecl->getTrailingWhereClause()) {
for (auto &req : WhereClause->getRequirements()) {
+ // If we're only looking at same-type constraints, skip everything
+ // else.
+ if (onlySameTypeConstraints &&
+ req.getKind() != RequirementReprKind::SameType)
+ continue;
+
auto innerSource =
FloatingRequirementSource::viaProtocolRequirement(
- Source, Proto, &req, /*inferred=*/false);
+ source, proto, &req, /*inferred=*/false);
addRequirement(&req, innerSource, &protocolSubMap, protoModule);
}
}
@@ -3066,7 +3161,7 @@
if (knownInherited == inheritedTypeDecls.end()) continue;
bool shouldWarnAboutRedeclaration =
- Source->kind == RequirementSource::RequirementSignatureSelf &&
+ source->kind == RequirementSource::RequirementSignatureSelf &&
assocTypeDecl->getDefaultDefinitionLoc().isNull();
for (auto inheritedType : knownInherited->second) {
// If we have inherited associated type...
@@ -3100,7 +3195,7 @@
// We inherited a type; this associated type will be identical
// to that typealias.
- if (Source->kind == RequirementSource::RequirementSignatureSelf) {
+ if (source->kind == RequirementSource::RequirementSignatureSelf) {
auto inheritedOwningDecl =
inheritedType->getDeclContext()
->getAsNominalTypeOrNominalTypeExtensionContext();
@@ -3124,7 +3219,7 @@
if (knownInherited == inheritedTypeDecls.end()) continue;
bool shouldWarnAboutRedeclaration =
- Source->kind == RequirementSource::RequirementSignatureSelf;
+ source->kind == RequirementSource::RequirementSignatureSelf;
for (auto inheritedType : knownInherited->second) {
// If we have inherited associated type...
@@ -3176,6 +3271,18 @@
return ConstraintResult::Resolved;
}
+ConstraintResult GenericSignatureBuilder::addConformanceRequirement(
+ PotentialArchetype *PAT,
+ ProtocolDecl *Proto,
+ const RequirementSource *Source) {
+ // Add the requirement, if we haven't done so already.
+ if (!PAT->addConformance(Proto, Source, *this))
+ return ConstraintResult::Resolved;
+
+ return expandConformanceRequirement(PAT, Proto, Source,
+ /*onlySameTypeRequirements=*/false);
+}
+
ConstraintResult GenericSignatureBuilder::addLayoutRequirementDirect(
PotentialArchetype *PAT,
LayoutConstraint Layout,
@@ -3468,11 +3575,10 @@
assert(allNested.back() == nestedPA);
if (allNested.size() > 1) {
auto firstPA = allNested.front();
- auto sameNamedSource =
- FloatingRequirementSource::forNestedTypeNameMatch(
- nestedPA->getNestedName());
+ auto quietlyInferredSource =
+ FloatingRequirementSource::forInferred(nullptr, /*quietly=*/true);
- addSameTypeRequirement(firstPA, nestedPA, sameNamedSource,
+ addSameTypeRequirement(firstPA, nestedPA, quietlyInferredSource,
UnresolvedHandlingKind::GenerateConstraints);
return;
}
@@ -4187,6 +4293,75 @@
}
} // 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 existingMembers = equivClass->members;
+ for (auto pa : existingMembers) {
+ // Make sure that there are only associated types the chain up to the
+ // parent.
+ bool foundNonAssociatedType = false;
+ for (auto currentPA = pa; auto parentPA = currentPA->getParent();
+ currentPA = parentPA){
+ if (!currentPA->getResolvedAssociatedType()) {
+ foundNonAssociatedType = true;
+ break;
+ }
+ }
+ if (foundNonAssociatedType) continue;
+
+ 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->getAffectedPotentialArchetype() == pa) {
+ 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, pa);
+
+ // Expand same-type constraints.
+ builder.expandConformanceRequirement(pa, proto, source,
+ /*onlySameTypeConstraints=*/true);
+ }
+ }
+}
+
+/// Retrieve the "local" archetype anchor for the given potential archetype,
+/// which rebuilds this potential archetype using the archetype anchors of
+/// the parent types.
+static PotentialArchetype *getLocalAnchor(PotentialArchetype *pa,
+ GenericSignatureBuilder &builder) {
+ auto parent = pa->getParent();
+ if (!parent) return pa;
+
+ auto parentAnchor = getLocalAnchor(parent, builder);
+ if (!parentAnchor) return pa;
+ auto localAnchor =
+ parentAnchor->getNestedArchetypeAnchor(
+ pa->getNestedName(), builder,
+ ArchetypeResolutionKind::CompleteWellFormed);
+ return localAnchor ? localAnchor : pa;
+}
+
void
GenericSignatureBuilder::finalize(SourceLoc loc,
ArrayRef<GenericTypeParamType *> genericParams,
@@ -4328,7 +4503,29 @@
checkConformanceConstraints(genericParams, archetype);
checkLayoutConstraints(genericParams, archetype);
- checkSameTypeConstraints(genericParams, archetype);
+ });
+
+ // FIXME: Expand all conformance requirements. This is expensive :(
+ visitPotentialArchetypes([&](PotentialArchetype *archetype) {
+ if (archetype != archetype->getRepresentative()) return;
+
+ // Make sure that we've build the archetype anchors for each potential
+ // archetype in this equivalence class. This is important to do for *all*
+ // potential archetypes because some non-archetype anchors will nonetheless
+ // be used in the canonicalized requirements.
+ for (auto pa : archetype->getEquivalenceClassMembers())
+ (void)getLocalAnchor(pa, *this);
+
+ if (auto equivClass = archetype->getEquivalenceClassIfPresent())
+ expandSameTypeConstraints(*this, equivClass);
+ });
+
+ // Check same-type constraints.
+ visitPotentialArchetypes([&](PotentialArchetype *archetype) {
+ if (archetype != archetype->getRepresentative()) return;
+
+ if (auto equivClass = archetype->getEquivalenceClassIfPresent())
+ checkSameTypeConstraints(genericParams, archetype);
});
// Check for generic parameters which have been made concrete or equated
@@ -4809,9 +5006,8 @@
///
/// \returns the best archetype anchor seen so far.
static PotentialArchetype *sameTypeDFS(PotentialArchetype *pa,
- unsigned component,
- llvm::SmallDenseMap<PotentialArchetype *, unsigned>
- &paToComponent) {
+ unsigned component,
+ llvm::SmallDenseMap<PotentialArchetype *, unsigned> &paToComponent) {
PotentialArchetype *anchor = pa;
// If we've already visited this potential archetype, we're done.
@@ -4819,10 +5015,16 @@
// Visit its adjacent potential archetypes.
for (const auto &constraint : pa->getSameTypeConstraints()) {
+ // Treat nested-type-name-match constraints specially.
+ if (constraint.source->getRoot()->kind ==
+ RequirementSource::NestedTypeNameMatch)
+ continue;
+
// Skip non-derived constraints.
if (!constraint.source->isDerivedRequirement()) continue;
- auto newAnchor = sameTypeDFS(constraint.value, component, paToComponent);
+ auto newAnchor =
+ sameTypeDFS(constraint.value, component, paToComponent);
// If this type is better than the anchor, use it for the anchor.
if (compareDependentTypes(&newAnchor, &anchor) < 0)
@@ -4839,23 +5041,6 @@
}
} // namespace swift
-/// Retrieve the "local" archetype anchor for the given potential archetype,
-/// which rebuilds this potential archetype using the archetype anchors of
-/// the parent types.
-static PotentialArchetype *getLocalAnchor(PotentialArchetype *pa,
- GenericSignatureBuilder &builder) {
- auto parent = pa->getParent();
- if (!parent) return pa;
-
- auto parentAnchor = getLocalAnchor(parent, builder);
- if (!parentAnchor) return pa;
- auto localAnchor =
- parentAnchor->getNestedArchetypeAnchor(
- pa->getNestedName(), builder,
- ArchetypeResolutionKind::CompleteWellFormed);
- return localAnchor ? localAnchor : pa;
-}
-
/// 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 of \c rep.
@@ -4933,9 +5118,6 @@
concrete.source->compare(bestConcreteTypeSource) < 0)
bestConcreteTypeSource = concrete.source;
}
-
- // Sort the components.
- llvm::array_pod_sort(components.begin(), components.end());
}
namespace {
@@ -4945,6 +5127,7 @@
unsigned source;
unsigned target;
Constraint<PotentialArchetype *> constraint;
+ bool isSelfDerived = false;
IntercomponentEdge(unsigned source, unsigned target,
const Constraint<PotentialArchetype *> &constraint)
@@ -4963,18 +5146,381 @@
// Prefer non-inferred requirement sources.
bool lhsIsInferred =
- lhs.constraint.source->isInferredRequirement(
- /*includeQuietInferred=*/false);
+ lhs.constraint.source->isInferredRequirement(
+ /*includeQuietInferred=*/false);
bool rhsIsInferred =
- rhs.constraint.source->isInferredRequirement(
- /*includeQuietInferred=*/false);
+ rhs.constraint.source->isInferredRequirement(
+ /*includeQuietInferred=*/false);
if (lhsIsInferred != rhsIsInferred)
return rhsIsInferred;;
return lhs.constraint < rhs.constraint;
}
+
+ LLVM_ATTRIBUTE_DEPRECATED(void dump() const,
+ "only for use in the debugger");
};
-} // end anonymous namespace
+}
+
+void IntercomponentEdge::dump() const {
+ llvm::errs() << constraint.archetype->getDebugName() << " -- "
+ << constraint.value->getDebugName() << ": ";
+ constraint.source->print(llvm::errs(), nullptr);
+ llvm::errs() << "\n";
+}
+
+/// 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);
+}
+
+/// 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<PotentialArchetype *, unsigned> &componentOf,
+ std::vector<IntercomponentEdge> &sameTypeEdges,
+ unsigned edgeIndex,
+ PotentialArchetype *from,
+ PotentialArchetype *to) {
+ // Which component are "from" and "to" in within the intercomponent edges?
+ assert(componentOf.count(from) > 0);
+ auto fromComponentIndex = componentOf[from];
+ assert(componentOf.count(to) > 0);
+ auto toComponentIndex = componentOf[to];
+
+ // 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 equivalance 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 bool isSelfDerivedNestedTypeNameMatchEdge(
+ EquivalenceClass *equivClass,
+ llvm::SmallDenseMap<PotentialArchetype *, unsigned> &componentOf,
+ std::vector<IntercomponentEdge> &sameTypeEdges,
+ unsigned edgeIndex) {
+ const auto &edge = sameTypeEdges[edgeIndex];
+ PotentialArchetype *source = edge.constraint.archetype;
+ PotentialArchetype *target = edge.constraint.value;
+ while (source->getParent() && target->getParent() &&
+ source->getResolvedAssociatedType() ==
+ target->getResolvedAssociatedType()) {
+ source = source->getParent();
+ target = target->getParent();
+
+ if (source->isInSameEquivalenceClassAs(target) &&
+ source->getEquivalenceClassIfPresent() == equivClass &&
+ !removalDisconnectsEquivalenceClass(equivClass, componentOf,
+ sameTypeEdges, edgeIndex,
+ source, target))
+ 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(
+ GenericSignatureBuilder &builder,
+ EquivalenceClass *equivClass,
+ llvm::SmallDenseMap<PotentialArchetype *, 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 = [&](Type type) {
+ CanType canType = type->getCanonicalType();
+ 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 componentOf[pa];
+
+ // 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({ }));
+ };
+
+ /// Local function to retrieve the component with which the given type is
+ /// associated, for a type that we haven't tried to resolve yet.
+ auto getUnknownTypeVirtualComponent = [&](Type type) {
+ if (auto pa =
+ builder.resolveArchetype(type,
+ ArchetypeResolutionKind::AlreadyKnown))
+ return getPotentialArchetypeVirtualComponent(pa);
+
+ return getTypeVirtualComponent(type);
+ };
+
+ 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 = getUnknownTypeVirtualComponent(delayedReq.lhs.get<Type>());
+
+ unsigned rhsComponent;
+ if (auto rhsPA = delayedReq.rhs.dyn_cast<PotentialArchetype *>())
+ rhsComponent = getPotentialArchetypeVirtualComponent(rhsPA);
+ else
+ rhsComponent = getUnknownTypeVirtualComponent(delayedReq.rhs.get<Type>());
+
+ // 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());
+}
+
+/// Check whether two potential archetypes "structurally" match, e.g.,
+/// the names match up to the root (which must match).
+static bool potentialArchetypesStructurallyMatch(PotentialArchetype *pa1,
+ PotentialArchetype *pa2) {
+ auto parent1 = pa1->getParent();
+ auto parent2 = pa2->getParent();
+ if (!parent1 && !parent2)
+ return pa1->getGenericParamKey() == pa2->getGenericParamKey();
+
+ // Check for depth mismatch.
+ if (static_cast<bool>(parent1) != static_cast<bool>(parent2))
+ return false;
+
+ // Check names.
+ if (pa1->getNestedName() != pa2->getNestedName())
+ return false;
+
+ return potentialArchetypesStructurallyMatch(parent1, parent2);
+}
+
+/// Look for structurally-equivalent types within the given equivalence class,
+/// collapsing their components.
+static void collapseStructurallyEquivalentSameTypeComponents(
+ EquivalenceClass *equivClass,
+ llvm::SmallDenseMap<PotentialArchetype *, unsigned> &componentOf,
+ SmallVectorImpl<unsigned> &collapsedParents,
+ unsigned &remainingComponents) {
+ for (unsigned i : indices(equivClass->members)) {
+ auto pa1 = equivClass->members[i];
+ auto rep1 = findRepresentative(collapsedParents, componentOf[pa1]);
+ for (unsigned j : indices(equivClass->members).slice(i + 1)) {
+ auto pa2 = equivClass->members[j];
+ auto rep2 = findRepresentative(collapsedParents, componentOf[pa2]);
+ if (rep1 == rep2) continue;
+
+ auto depth = pa1->getNestingDepth();
+ if (depth < 2 || depth != pa2->getNestingDepth()) continue;
+
+ if (potentialArchetypesStructurallyMatch(pa1, pa2) &&
+ unionSets(collapsedParents, rep1, rep2)) {
+ --remainingComponents;
+ rep1 = findRepresentative(collapsedParents, componentOf[pa1]);
+ }
+ }
+ }
+}
+
+/// 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<PotentialArchetype *, 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(equivClass, componentOf,
+ sameTypeEdges, edgeIndex)) {
+ auto eraseConstraint = [&](PotentialArchetype *archetype) {
+ auto &constraints = equivClass->sameTypeConstraints[archetype];
+ auto known =
+ std::find_if(constraints.begin(), constraints.end(),
+ [&](const Constraint<PotentialArchetype *> &existing) {
+ // Check the requirement source, first.
+ if (existing.source != edge.constraint.source)
+ return false;
+
+ return
+ (existing.archetype == edge.constraint.archetype &&
+ existing.value == edge.constraint.value) ||
+ (existing.archetype == edge.constraint.value &&
+ existing.value == edge.constraint.archetype);
+ });
+ assert(known != constraints.end());
+ constraints.erase(known);
+ };
+
+ // Note that this edge is self-derived, so we don't consider it again.
+ edge.isSelfDerived = true;
+
+ // Erase the constraint in both directions.
+ eraseConstraint(edge.constraint.archetype);
+ eraseConstraint(edge.constraint.value);
+
+ 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(
+ builder, equivClass, componentOf, collapsedParents, remainingComponents);
+ }
+
+ if (remainingComponents > 1) {
+ // Collapse structurally-equivalent components.
+ collapseStructurallyEquivalentSameTypeComponents(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.anchor, 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.anchor, &newComponent.anchor) < 0)
+ newComponent.anchor = oldComponent.anchor;
+
+ // 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(
ArrayRef<GenericTypeParamType *> genericParams,
@@ -4983,16 +5529,6 @@
if (!equivClass || !equivClass->derivedSameTypeComponents.empty())
return;
- // Make sure that we've build the archetype anchors for each potential
- // archetype in this equivalence class. This is important to do for *all*
- // potential archetypes because some non-archetype anchors will nonetheless
- // be used in the canonicalized requirements.
- for (auto pa : pa->getEquivalenceClassMembers()) {
- (void)getLocalAnchor(pa, *this);
- }
- equivClass = pa->getEquivalenceClassIfPresent();
- assert(equivClass && "Equivalence class disappeared?");
-
bool anyDerivedViaConcrete = false;
for (auto &entry : equivClass->sameTypeConstraints) {
auto &constraints = entry.second;
@@ -5025,6 +5561,7 @@
// Intercomponent edges are stored as one big list, which tracks the
// source/target components.
std::vector<IntercomponentEdge> intercomponentEdges;
+ std::vector<IntercomponentEdge> nestedTypeNameMatchEdges;
for (auto &entry : equivClass->sameTypeConstraints) {
auto &constraints = entry.second;
for (const auto &constraint : constraints) {
@@ -5054,15 +5591,27 @@
// Determine which component each of the source/destination fall into.
assert(componentOf.count(constraint.archetype) > 0 &&
"unknown potential archetype?");
- unsigned firstComponent = componentOf[constraint.archetype];
+ unsigned firstComponentIdx = componentOf[constraint.archetype];
assert(componentOf.count(constraint.value) > 0 &&
"unknown potential archetype?");
- unsigned secondComponent = componentOf[constraint.value];
+ unsigned secondComponentIdx = componentOf[constraint.value];
+
+ // 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 (firstComponent == secondComponent) {
- intracomponentEdges[firstComponent].push_back(constraint);
+ if (firstComponentIdx == secondComponentIdx) {
+ intracomponentEdges[firstComponentIdx].push_back(constraint);
continue;
}
@@ -5072,7 +5621,7 @@
// Ignore inferred requirements; we don't want to diagnose them.
intercomponentEdges.push_back(
- IntercomponentEdge(firstComponent, secondComponent, constraint));
+ IntercomponentEdge(firstComponentIdx, secondComponentIdx, constraint));
}
}
@@ -5084,7 +5633,6 @@
// Remove derived-via-concrete constraints.
(void)removeSelfDerived(constraints, /*proto=*/nullptr);
- anyDerivedViaConcrete = true;
}
}
@@ -5097,7 +5645,12 @@
checkConstraintList<PotentialArchetype *, Type>(
genericParams, constraints,
[](const Constraint<PotentialArchetype *> &) { return true; },
- [](const Constraint<PotentialArchetype *> &) {
+ [](const Constraint<PotentialArchetype *> &constraint) {
+ // Ignore nested-type-name-match constraints.
+ if (constraint.source->getRoot()->kind ==
+ RequirementSource::NestedTypeNameMatch)
+ return ConstraintRelation::Unrelated;
+
return ConstraintRelation::Redundant;
},
None,
@@ -5190,6 +5743,9 @@
connected[edge.target] = true;
}
}
+
+ collapseSameTypeComponents(*this, equivClass, componentOf,
+ nestedTypeNameMatchEdges);
}
/// Resolve any unresolved dependent member types using the given builder.
@@ -5486,7 +6042,8 @@
// If we're at the last anchor in the component, do nothing;
auto nextAnchor = knownAnchor;
++nextAnchor;
- if (nextAnchor != equivClass->derivedSameTypeComponents.end()) {
+ if (nextAnchor != equivClass->derivedSameTypeComponents.end() /* &&
+ !equivClass->areAllRequirementsDerived()*/) {
// Form a same-type constraint from this anchor within the component
// to the next.
// FIXME: Distinguish between explicit and inferred here?
diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp
index 439ea5d..f3a713f 100644
--- a/lib/Sema/TypeCheckProtocol.cpp
+++ b/lib/Sema/TypeCheckProtocol.cpp
@@ -4157,6 +4157,60 @@
return TC.compareDeclarations(DC, decl1, decl2);
}
+/// "Sanitize" requirements for conformance checking, removing any requirements
+/// that unnecessarily refer to associated types of other protocols.
+static void sanitizeProtocolRequirements(
+ ProtocolDecl *proto,
+ ArrayRef<Requirement> requirements,
+ SmallVectorImpl<Requirement> &sanitized) {
+ std::function<Type(Type)> sanitizeType;
+ sanitizeType = [&](Type outerType) {
+ return outerType.transformRec([&] (TypeBase *type) -> Optional<Type> {
+ if (auto depMemTy = dyn_cast<DependentMemberType>(type)) {
+ if (!depMemTy->getAssocType() ||
+ depMemTy->getAssocType()->getProtocol() != proto) {
+ for (auto member : proto->lookupDirect(depMemTy->getName())) {
+ if (auto assocType = dyn_cast<AssociatedTypeDecl>(member)) {
+ return Type(DependentMemberType::get(
+ sanitizeType(depMemTy->getBase()),
+ assocType));
+ }
+ }
+
+ if (depMemTy->getBase()->is<GenericTypeParamType>())
+ return Type();
+ }
+ }
+
+ return None;
+ });
+ };
+
+ for (const auto &req : requirements) {
+ switch (req.getKind()) {
+ case RequirementKind::Conformance:
+ case RequirementKind::SameType:
+ case RequirementKind::Superclass: {
+ Type firstType = sanitizeType(req.getFirstType());
+ Type secondType = sanitizeType(req.getSecondType());
+ if (firstType && secondType) {
+ sanitized.push_back({req.getKind(), firstType, secondType});
+ }
+ break;
+ }
+
+ case RequirementKind::Layout: {
+ Type firstType = sanitizeType(req.getFirstType());
+ if (firstType) {
+ sanitized.push_back({req.getKind(), firstType,
+ req.getLayoutConstraint()});
+ }
+ break;
+ }
+ }
+ }
+}
+
void ConformanceChecker::resolveTypeWitnesses() {
llvm::SetVector<AssociatedTypeDecl *> unresolvedAssocTypes;
@@ -4424,9 +4478,12 @@
Proto, Conformance->getType(),
ProtocolConformanceRef(Conformance));
+ SmallVector<Requirement, 4> sanitizedRequirements;
+ sanitizeProtocolRequirements(Proto, Proto->getRequirementSignature(),
+ sanitizedRequirements);
auto requirementSig =
GenericSignature::get({Proto->getProtocolSelfType()},
- Proto->getRequirementSignature());
+ sanitizedRequirements);
auto result =
TC.checkGenericArguments(DC, SourceLoc(), SourceLoc(),
Conformance->getType(), requirementSig,
diff --git a/stdlib/public/core/UTFEncoding.swift b/stdlib/public/core/UTFEncoding.swift
index 1a257b7..bab890a 100644
--- a/stdlib/public/core/UTFEncoding.swift
+++ b/stdlib/public/core/UTFEncoding.swift
@@ -17,7 +17,7 @@
public protocol _UTFParser {
- associatedtype Encoding : _UnicodeEncoding_
+ associatedtype Encoding : _UnicodeEncoding
func _parseMultipleCodeUnits() -> (isValid: Bool, bitCount: UInt8)
func _bufferedScalar(bitCount: UInt8) -> Encoding.EncodedScalar
diff --git a/stdlib/public/core/UnicodeEncoding.swift b/stdlib/public/core/UnicodeEncoding.swift
index 2bde99e..ca81fab 100644
--- a/stdlib/public/core/UnicodeEncoding.swift
+++ b/stdlib/public/core/UnicodeEncoding.swift
@@ -10,7 +10,7 @@
//
//===----------------------------------------------------------------------===//
-public protocol _UnicodeEncoding_ {
+public protocol _UnicodeEncoding {
/// The basic unit of encoding
associatedtype CodeUnit : UnsignedInteger, FixedWidthInteger
@@ -44,12 +44,12 @@
/// A type that can be used to parse `CodeUnits` into
/// `EncodedScalar`s.
associatedtype ForwardParser : Unicode.Parser
- // where ForwardParser.Encoding == Self
+ where ForwardParser.Encoding == Self
/// A type that can be used to parse a reversed sequence of
/// `CodeUnits` into `EncodedScalar`s.
associatedtype ReverseParser : Unicode.Parser
- // where ReverseParser.Encoding == Self
+ where ReverseParser.Encoding == Self
//===--------------------------------------------------------------------===//
// FIXME: this requirement shouldn't be here and is mitigated by the default
@@ -60,15 +60,10 @@
static func _isScalar(_ x: CodeUnit) -> Bool
}
-extension _UnicodeEncoding_ {
+extension _UnicodeEncoding {
// See note on declaration of requirement, above
public static func _isScalar(_ x: CodeUnit) -> Bool { return false }
-}
-public protocol _UnicodeEncoding : _UnicodeEncoding_
-where ForwardParser.Encoding == Self, ReverseParser.Encoding == Self {}
-
-extension _UnicodeEncoding_ {
public static func transcode<FromEncoding : Unicode.Encoding>(
_ content: FromEncoding.EncodedScalar, from _: FromEncoding.Type
) -> EncodedScalar? {
diff --git a/stdlib/public/core/UnicodeParser.swift b/stdlib/public/core/UnicodeParser.swift
index 0a5ee64..adc4a26 100644
--- a/stdlib/public/core/UnicodeParser.swift
+++ b/stdlib/public/core/UnicodeParser.swift
@@ -43,7 +43,7 @@
/// scalar values.
public protocol _UnicodeParser {
/// The encoding with which this parser is associated
- associatedtype Encoding : _UnicodeEncoding_
+ associatedtype Encoding : _UnicodeEncoding
/// Constructs an instance that can be used to begin parsing `CodeUnit`s at
/// any Unicode scalar boundary.
diff --git a/test/Generics/protocol_requirement_signatures.swift b/test/Generics/protocol_requirement_signatures.swift
index 2bb7d20..e3fd609 100644
--- a/test/Generics/protocol_requirement_signatures.swift
+++ b/test/Generics/protocol_requirement_signatures.swift
@@ -33,16 +33,16 @@
// inheritance without any new requirements
// CHECK-LABEL: .Q3@
-// CHECK-NEXT: Requirement signature: <Self where Self : Q1>
-// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : Q1>
+// CHECK-NEXT: Requirement signature: <Self where Self : Q1, Self.X == Self.X>
+// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : Q1, τ_0_0.X == τ_0_0.X>
protocol Q3: Q1 {
associatedtype X // expected-warning{{redeclaration of associated type 'X'}}
}
// inheritance adding a new conformance
// CHECK-LABEL: .Q4@
-// CHECK-NEXT: Requirement signature: <Self where Self : Q1, Self.X : P2>
-// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : Q1, τ_0_0.X : P2>
+// CHECK-NEXT: Requirement signature: <Self where Self : Q1, Self.X : P2, Self.X == Self.X>
+// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : Q1, τ_0_0.X : P2, τ_0_0.X == τ_0_0.X>
protocol Q4: Q1 {
associatedtype X: P2 // expected-warning{{redeclaration of associated type 'X'}}
// expected-note@-1 2{{'X' declared here}}
@@ -56,8 +56,8 @@
// multiple inheritance without any new requirements
// CHECK-LABEL: .Q6@
-// CHECK-NEXT: Requirement signature: <Self where Self : Q2, Self : Q3, Self : Q4>
-// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : Q2, τ_0_0 : Q3, τ_0_0 : Q4>
+// CHECK-NEXT: Requirement signature: <Self where Self : Q2, Self : Q3, Self : Q4, Self.X == Self.X>
+// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : Q2, τ_0_0 : Q3, τ_0_0 : Q4, τ_0_0.X == τ_0_0.X>
protocol Q6: Q2, // expected-note{{conformance constraint 'Self.X': 'P1' implied here}}
Q3, Q4 {
associatedtype X: P1 // expected-warning{{redundant conformance constraint 'Self.X': 'P1'}}
@@ -66,8 +66,8 @@
// multiple inheritance with a new conformance
// CHECK-LABEL: .Q7@
-// CHECK-NEXT: Requirement signature: <Self where Self : Q2, Self : Q3, Self : Q4, Self.X : P3>
-// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : Q2, τ_0_0 : Q3, τ_0_0 : Q4, τ_0_0.X : P3>
+// CHECK-NEXT: Requirement signature: <Self where Self : Q2, Self : Q3, Self : Q4, Self.X : P3, Self.X == Self.X>
+// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : Q2, τ_0_0 : Q3, τ_0_0 : Q4, τ_0_0.X : P3, τ_0_0.X == τ_0_0.X>
protocol Q7: Q2, Q3, Q4 {
associatedtype X: P3 // expected-warning{{redeclaration of associated type 'X'}}
}
diff --git a/test/Generics/requirement_inference.swift b/test/Generics/requirement_inference.swift
index 390aafa..755d24d 100644
--- a/test/Generics/requirement_inference.swift
+++ b/test/Generics/requirement_inference.swift
@@ -176,11 +176,11 @@
}
// CHECK-LABEL: sameTypeConcrete1@
-// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : P10, τ_0_0 : P9, τ_0_0.A == X3, τ_0_0.B == Int, τ_0_0.C == Int>
+// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : P10, τ_0_0 : P9, τ_0_0.A == X3, τ_0_0.A == X3, τ_0_0.B == Int, τ_0_0.C == Int>
func sameTypeConcrete1<T : P9 & P10>(_: T) where T.A == X3, T.C == T.B, T.C == Int { }
// CHECK-LABEL: sameTypeConcrete2@
-// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : P10, τ_0_0 : P9, τ_0_0.B == X3, τ_0_0.C == X3>
+// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : P10, τ_0_0 : P9, τ_0_0.A == τ_0_0.A, τ_0_0.B == X3, τ_0_0.C == X3>
func sameTypeConcrete2<T : P9 & P10>(_: T) where T.B : X3, T.C == T.B, T.C == X3 { }
// expected-warning@-1{{redundant superclass constraint 'T.B' : 'X3'}}
// expected-note@-2{{same-type constraint 'T.C' == 'X3' written here}}
@@ -188,7 +188,7 @@
// Note: a standard-library-based stress test to make sure we don't inject
// any additional requirements.
// CHECK-LABEL: RangeReplaceableCollection.f()@
-// CHECK: <τ_0_0 where τ_0_0 : MutableCollection, τ_0_0 : RangeReplaceableCollection, τ_0_0.SubSequence == MutableRangeReplaceableSlice<τ_0_0>>
+// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : MutableCollection, τ_0_0 : RangeReplaceableCollection, τ_0_0.SubSequence == MutableRangeReplaceableSlice<τ_0_0>>
extension RangeReplaceableCollection where
Self: MutableCollection,
Self.SubSequence == MutableRangeReplaceableSlice<Self>
@@ -399,8 +399,25 @@
}
// CHECK-LABEL: .P28@
-// CHECK-NEXT: Requirement signature: <Self where Self : P3>
-// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : P3>
+// CHECK-NEXT: Requirement signature: <Self where Self : P3, Self.P3Assoc == X28>
+// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : P3, τ_0_0.P3Assoc == X28>
protocol P28: P3 {
typealias P3Assoc = X28 // expected-warning{{typealias overriding associated type}}
}
+
+// ----------------------------------------------------------------------------
+// Inference of associated types by name match
+// ----------------------------------------------------------------------------
+protocol P29 {
+ associatedtype X
+}
+
+protocol P30 {
+ associatedtype X
+}
+
+protocol P31 { }
+
+// CHECK-LABEL: .sameTypeNameMatch1@
+// Generic signature: <T where T : P29, T : P30, T.X : P31, T.X == T.X>
+func sameTypeNameMatch1<T: P29 & P30>(_: T) where T.X: P31 { }
diff --git a/test/SILGen/same_type_abstraction.swift b/test/SILGen/same_type_abstraction.swift
index fb84d6b..9da1a8e 100644
--- a/test/SILGen/same_type_abstraction.swift
+++ b/test/SILGen/same_type_abstraction.swift
@@ -50,7 +50,7 @@
}
extension Refined {
- // CHECK-LABEL: sil hidden @_T021same_type_abstraction7RefinedPAAEx3KeyQz12withElements_tcfC : $@convention(method) <Self where Self : Refined> (@in Self.Key, @thick Self.Type) -> @out Self
+ // CHECK-LABEL: sil hidden @_T021same_type_abstraction7RefinedPAAEx5AssocQz12withElements_tcfC : $@convention(method) <Self where Self : Refined> (@in Self.Assoc, @thick Self.Type) -> @out Self
init(withElements newElements: Key) {
self.init()
}
diff --git a/test/decl/protocol/recursive_requirement_ok.swift b/test/decl/protocol/recursive_requirement_ok.swift
index cb07937..2266500 100644
--- a/test/decl/protocol/recursive_requirement_ok.swift
+++ b/test/decl/protocol/recursive_requirement_ok.swift
@@ -20,7 +20,7 @@
associatedtype X : P2
}
-// CHECK: P2
+// CHECK-LABEL: .P2@
// CHECK: Requirement signature: <Self where Self == Self.Y.X, Self.Y : P1, Self.Z : P1>
protocol P2 {
associatedtype Y : P1 where Y.X == Self
@@ -32,9 +32,55 @@
associatedtype X : P4
}
-// CHECK: .P4@
+// CHECK-LABEL: .P4@
// CHECK: Requirement signature: <Self where Self == Self.Y.X, Self.Y : P3, Self.Z : P3, Self.Y.X == Self.Z.X>
protocol P4 {
associatedtype Y: P3 where Y.X == Self
associatedtype Z: P3 where Z.X == Self
}
+
+protocol P5 {
+ associatedtype X : P5
+ where X.X == X
+}
+
+// CHECK-LABEL: .P6@
+// CHECK: Requirement signature: <Self where Self : P5, Self.Y : P5>
+protocol P6 : P5 {
+ associatedtype Y : P5
+}
+
+// CHECK: Generic signature: <Self where Self : P6, Self.X == Self.Y.X>
+extension P6 where X == Y.X { }
+
+// SR-5601
+protocol P7 {
+ associatedtype X: P9 where X.Q == Self, X.R == UInt8
+ associatedtype Y: P9 where Y.Q == Self, Y.R == UInt16
+ // NOTE: Removing either X or Y from P7 (and A7) makes the program compile.
+}
+struct A7: P7 {
+ typealias X = S9<UInt8>
+ typealias Y = S9<UInt16>
+}
+protocol P8 { }
+protocol P9 : P8 { // NOTE: Removing ": P8 " here makes the program compile.
+ associatedtype Q: P7
+ associatedtype R
+}
+struct S9<E> : P9 {
+ typealias R = E
+ typealias Q = A7
+}
+
+// SR-5610
+protocol P10 {
+ associatedtype X : P11 where X.Q == Self
+}
+protocol P11 {
+ associatedtype Q : P10
+
+ // CHECK-LABEL: .P11.map@
+ // CHECK: Generic signature: <Self, T where Self : P11, T : P11, Self.Q == T.Q>
+ func map<T>(_: T.Type) where T : P11, Q == T.Q
+}