Merge pull request #12097 from DougGregor/gsb-nested-type-lookup
[GSB] Centralize, clean up, and cache nested type name lookup
diff --git a/include/swift/AST/GenericSignatureBuilder.h b/include/swift/AST/GenericSignatureBuilder.h
index ddf8ebe..8eecc19 100644
--- a/include/swift/AST/GenericSignatureBuilder.h
+++ b/include/swift/AST/GenericSignatureBuilder.h
@@ -215,6 +215,15 @@
/// a superclass requirement.
bool isConformanceSatisfiedBySuperclass(ProtocolDecl *proto) const;
+ /// Lookup a nested type with the given name within this equivalence
+ /// class.
+ ///
+ /// \param otherConcreteTypes If non-null, will be filled in the all of the
+ /// concrete types we found (other than the result) with the same name.
+ TypeDecl *lookupNestedType(
+ Identifier name,
+ SmallVectorImpl<TypeDecl *> *otherConcreteTypes = nullptr);
+
/// Dump a debugging representation of this equivalence class.
void dump(llvm::raw_ostream &out) const;
@@ -232,6 +241,17 @@
/// anchor was cached.
unsigned numMembers;
} archetypeAnchorCache;
+
+ /// Describes a cached nested type.
+ struct CachedNestedType {
+ unsigned numConformancesPresent;
+ CanType superclassPresent;
+ llvm::TinyPtrVector<TypeDecl *> types;
+ };
+
+ /// Cached nested-type information, which contains the best declaration
+ /// for a given name.
+ llvm::SmallDenseMap<Identifier, CachedNestedType> nestedTypeNameCache;
};
friend class RequirementSource;
@@ -522,9 +542,6 @@
/// \brief Add all of a generic signature's parameters and requirements.
void addGenericSignature(GenericSignature *sig);
- /// \brief Build the generic signature.
- GenericSignature *getGenericSignature();
-
/// Infer requirements from the given type, recursively.
///
/// This routine infers requirements from a type that occurs within the
@@ -558,11 +575,13 @@
/// \brief Finalize the set of requirements and compute the generic
/// signature.
///
- /// After this point, one cannot introduce new requirements.
+ /// After this point, one cannot introduce new requirements, and the
+ /// generic signature builder no longer has valid state.
GenericSignature *computeGenericSignature(
SourceLoc loc,
- bool allowConcreteGenericParams = false);
+ bool allowConcreteGenericParams = false) &&;
+private:
/// Finalize the set of requirements, performing any remaining checking
/// required before generating archetypes.
///
@@ -572,6 +591,7 @@
ArrayRef<GenericTypeParamType *> genericParams,
bool allowConcreteGenericParams=false);
+public:
/// Process any delayed requirements that can be handled now.
void processDelayedRequirements();
@@ -1490,6 +1510,12 @@
return parentOrBuilder.dyn_cast<PotentialArchetype *>();
}
+ /// Retrieve the type declaration to which this nested type was resolved.
+ TypeDecl *getResolvedType() const {
+ assert(getParent() && "Not an associated type");
+ return identifier.assocTypeOrConcrete;
+ }
+
/// Retrieve the associated type to which this potential archetype
/// has been resolved.
AssociatedTypeDecl *getResolvedAssociatedType() const {
@@ -1632,13 +1658,8 @@
ArchetypeResolutionKind kind,
GenericSignatureBuilder &builder);
- /// \brief Retrieve (or create) a nested type with a known associated type.
- PotentialArchetype *getNestedType(AssociatedTypeDecl *assocType,
- GenericSignatureBuilder &builder);
-
- /// \brief Retrieve (or create) a nested type with a known concrete type
- /// declaration.
- PotentialArchetype *getNestedType(TypeDecl *concreteDecl,
+ /// \brief Retrieve (or create) a nested type with a known type.
+ PotentialArchetype *getNestedType(TypeDecl *type,
GenericSignatureBuilder &builder);
/// \brief Retrieve (or create) a nested type that is the current best
@@ -1658,8 +1679,8 @@
/// type or typealias of the given protocol, unless the \c kind implies that
/// a potential archetype should not be created if it's missing.
PotentialArchetype *updateNestedTypeForConformance(
- PointerUnion<AssociatedTypeDecl *, TypeDecl *> type,
- ArchetypeResolutionKind kind);
+ TypeDecl *type,
+ ArchetypeResolutionKind kind);
/// Update the named nested type when we know this type conforms to the given
/// protocol.
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 7917da8..5bb5519 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -4591,7 +4591,7 @@
GenericSignatureBuilder::FloatingRequirementSource::forAbstract();
builder.addRequirement(requirement, source, nullptr);
- CanGenericSignature genericSig(builder.computeGenericSignature(SourceLoc()));
+ CanGenericSignature genericSig(std::move(builder).computeGenericSignature(SourceLoc()));
auto result = Impl.ExistentialSignatures.insert(
std::make_pair(existential, genericSig));
diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp
index a7c473a..f9af2d2 100644
--- a/lib/AST/Builtins.cpp
+++ b/lib/AST/Builtins.cpp
@@ -491,7 +491,8 @@
Builder.addGenericParameter(gp);
}
- auto GenericSig = Builder.computeGenericSignature(SourceLoc());
+ auto GenericSig =
+ std::move(Builder).computeGenericSignature(SourceLoc());
GenericEnv = GenericSig->createGenericEnvironment(*ctx.TheBuiltinModule);
}
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index bcb698a..e7e7f55 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -3419,7 +3419,8 @@
nullptr);
// Compute and record the signature.
- auto requirementSig = builder.computeGenericSignature(SourceLoc());
+ auto requirementSig =
+ std::move(builder).computeGenericSignature(SourceLoc());
RequirementSignature = requirementSig->getRequirements().data();
assert(RequirementSignature != nullptr);
NumRequirementsInSignature = requirementSig->getRequirements().size();
diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp
index f0b85ea..32f8d63 100644
--- a/lib/AST/GenericSignatureBuilder.cpp
+++ b/lib/AST/GenericSignatureBuilder.cpp
@@ -76,6 +76,10 @@
"# 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,
@@ -1554,6 +1558,159 @@
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;
+
+ // - 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 = ProtocolType::compareProtocols(&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;
+}
+
+TypeDecl *EquivalenceClass::lookupNestedType(
+ 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())) {
+ ++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,
+ /*ignoreNewExtensions=*/true)) {
+ // 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)) {
+ if (!bestAssocType ||
+ compareAssociatedTypes(assocType, bestAssocType) < 0)
+ bestAssocType = assocType;
+
+ continue;
+ }
+
+ // If this is another type declaration, determine whether we should
+ // record it.
+ if (auto type = dyn_cast<TypeDecl>(member)) {
+ // FIXME: Filter out type declarations that aren't in the same
+ // module as the protocol itself. This is an unprincipled hack, but
+ // provides consistent lookup semantics for the generic signature
+ // builder in all contents.
+ if (type->getDeclContext()->getParentModule()
+ != proto->getParentModule())
+ continue;
+
+ // Resolve the signature of this type.
+ if (!type->hasInterfaceType()) {
+ type->getASTContext().getLazyResolver()->resolveDeclSignature(type);
+ if (!type->hasInterfaceType())
+ continue;
+ }
+
+ concreteDecls.push_back(type);
+ continue;
+ }
+ }
+ }
+
+ // If we haven't found anything yet but have a superclass, look for a type
+ // in the superclass.
+ // FIXME: Shouldn't we always look in the superclass?
+ if (!bestAssocType && concreteDecls.empty() && superclass) {
+ if (auto classDecl = superclass->getClassOrBoundGenericClass()) {
+ SmallVector<ValueDecl *, 2> superclassMembers;
+ classDecl->getParentModule()->lookupQualified(
+ superclass, name,
+ NL_QualifiedDefault | NL_OnlyTypes | NL_ProtocolMembers, nullptr,
+ superclassMembers);
+ for (auto member : superclassMembers) {
+ if (auto type = dyn_cast<TypeDecl>(member)) {
+ // Resolve the signature of this type.
+ if (!type->hasInterfaceType()) {
+ type->getASTContext().getLazyResolver()->resolveDeclSignature(type);
+ if (!type->hasInterfaceType())
+ continue;
+ }
+
+ concreteDecls.push_back(type);
+ }
+ }
+ }
+ }
+
+ // Form the new cache entry.
+ CachedNestedType entry;
+ entry.numConformancesPresent = conformsTo.size();
+ entry.superclassPresent =
+ superclass ? superclass->getCanonicalType() : CanType();
+ if (bestAssocType) {
+ entry.types.push_back(bestAssocType);
+ entry.types.insert(entry.types.end(),
+ concreteDecls.begin(), concreteDecls.end());
+ } else if (!concreteDecls.empty()) {
+ // Find the best concrete type.
+ auto bestConcreteTypeIter =
+ std::min_element(concreteDecls.begin(), concreteDecls.end(),
+ [](TypeDecl *type1, TypeDecl *type2) {
+ return TypeDecl::compare(type1, type2) < 0;
+ });
+
+ // 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)));
+}
+
void EquivalenceClass::dump(llvm::raw_ostream &out) const {
out << "Equivalence class represented by "
<< members.front()->getRepresentative()->getDebugName() << ":\n";
@@ -1961,28 +2118,6 @@
return result;
}
-/// 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;
-
- // - 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 = ProtocolType::compareProtocols(&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;
-}
-
/// Whether there are any concrete type declarations in the potential archetype.
static bool hasConcreteDecls(const PotentialArchetype *pa) {
auto parent = pa->getParent();
@@ -2210,16 +2345,9 @@
}
PotentialArchetype *PotentialArchetype::getNestedType(
- AssociatedTypeDecl *assocType,
+ TypeDecl *type,
GenericSignatureBuilder &builder) {
- return updateNestedTypeForConformance(assocType,
- ArchetypeResolutionKind::WellFormed);
-}
-
-PotentialArchetype *PotentialArchetype::getNestedType(
- TypeDecl *getConcreteTypeDecl,
- GenericSignatureBuilder &builder) {
- return updateNestedTypeForConformance(getConcreteTypeDecl,
+ return updateNestedTypeForConformance(type,
ArchetypeResolutionKind::WellFormed);
}
@@ -2227,94 +2355,21 @@
Identifier name,
GenericSignatureBuilder &builder,
ArchetypeResolutionKind kind) {
- // Look for the best associated type or concrete type within the protocols
- // we know about.
- AssociatedTypeDecl *bestAssocType = nullptr;
- TypeDecl *bestConcreteDecl = nullptr;
SmallVector<TypeDecl *, 4> concreteDecls;
- auto rep = getRepresentative();
- for (auto proto : rep->getConformsTo()) {
- // Look for an associated type and/or concrete type with this name.
- AssociatedTypeDecl *assocType = nullptr;
- TypeDecl *concreteDecl = nullptr;
- for (auto member : proto->lookupDirect(name,
- /*ignoreNewExtensions=*/true)) {
- if (!assocType)
- assocType = dyn_cast<AssociatedTypeDecl>(member);
+ auto bestType =
+ getOrCreateEquivalenceClass()->lookupNestedType(name, &concreteDecls);
- // FIXME: Filter out type declarations that aren't in the protocol itself?
- if (!concreteDecl && !isa<AssociatedTypeDecl>(member)) {
- if (!member->hasInterfaceType())
- builder.getLazyResolver()->resolveDeclSignature(member);
- if (member->hasInterfaceType())
- concreteDecl = dyn_cast<TypeDecl>(member);
- }
- }
+ // We didn't find any type with this name.
+ if (!bestType) return nullptr;
- if (assocType &&
- (!bestAssocType ||
- compareAssociatedTypes(assocType, bestAssocType) < 0))
- bestAssocType = assocType;
-
- if (concreteDecl) {
- // Record every concrete type.
- concreteDecls.push_back(concreteDecl);
-
- // Track the best concrete type.
- if (!bestConcreteDecl ||
- TypeDecl::compare(concreteDecl, bestConcreteDecl) < 0)
- bestConcreteDecl = concreteDecl;
- }
- }
-
- // If we found an associated type, use it.
- PotentialArchetype *resultPA = nullptr;
- if (bestAssocType) {
- resultPA = updateNestedTypeForConformance(bestAssocType, kind);
- }
-
- // If we have an associated type, drop any concrete decls that aren't in
- // the same module as the protocol.
- // FIXME: This is an unprincipled hack for an unprincipled feature.
- concreteDecls.erase(
- std::remove_if(concreteDecls.begin(), concreteDecls.end(),
- [&](TypeDecl *concreteDecl) {
- return concreteDecl->getDeclContext()->getParentModule() !=
- concreteDecl->getDeclContext()
- ->getAsNominalTypeOrNominalTypeExtensionContext()->getParentModule();
- }),
- concreteDecls.end());
-
- // If we haven't found anything yet but have a superclass, look for a type
- // in the superclass.
- if (!resultPA && concreteDecls.empty()) {
- if (auto superclass = getSuperclass()) {
- if (auto classDecl = superclass->getClassOrBoundGenericClass()) {
- SmallVector<ValueDecl *, 2> superclassMembers;
- classDecl->getParentModule()->lookupQualified(superclass, name, NL_QualifiedDefault | NL_OnlyTypes | NL_ProtocolMembers, nullptr,
- superclassMembers);
- for (auto member : superclassMembers) {
- if (auto concreteDecl = dyn_cast<TypeDecl>(member)) {
- // Track the best concrete type.
- if (!bestConcreteDecl ||
- TypeDecl::compare(concreteDecl, bestConcreteDecl) < 0)
- bestConcreteDecl = concreteDecl;
-
- concreteDecls.push_back(concreteDecl);
- }
- }
- }
- }
- }
+ // Resolve the nested type.
+ auto resultPA = updateNestedTypeForConformance(bestType, kind);
// Update for all of the concrete decls with this name, which will introduce
// various same-type constraints.
for (auto concreteDecl : concreteDecls) {
- auto concreteDeclPA = updateNestedTypeForConformance(
- concreteDecl,
- ArchetypeResolutionKind::WellFormed);
- if (!resultPA && concreteDecl == bestConcreteDecl)
- resultPA = concreteDeclPA;
+ (void)updateNestedTypeForConformance(concreteDecl,
+ ArchetypeResolutionKind::WellFormed);
}
return resultPA;
@@ -2325,43 +2380,22 @@
Identifier name,
ProtocolDecl *proto,
ArchetypeResolutionKind kind) {
- /// Determine whether there is an associated type or concrete type with this
- /// name in this protocol. If not, there's nothing to do.
- AssociatedTypeDecl *assocType = nullptr;
- TypeDecl *concreteDecl = nullptr;
- for (auto member : proto->lookupDirect(name, /*ignoreNewExtensions=*/true)) {
- if (!assocType)
- assocType = dyn_cast<AssociatedTypeDecl>(member);
+ // Lookup the best type for this name.
+ auto bestType =
+ getOrCreateEquivalenceClass()->lookupNestedType(name, nullptr);
+ if (!bestType) return nullptr;
- // FIXME: Filter out concrete types that aren't in the protocol itself?
- if (!concreteDecl && !isa<AssociatedTypeDecl>(member)) {
- if (!member->hasInterfaceType())
- proto->getASTContext().getLazyResolver()->resolveDeclSignature(member);
- if (member->hasInterfaceType())
- concreteDecl = dyn_cast<TypeDecl>(member);
- }
- }
-
- // There is no associated type or concrete type with this name in this
- // protocol
- if (!assocType && !concreteDecl)
- return nullptr;
-
- // If we had both an associated type and a concrete type, ignore the latter.
- // This is for ill-formed code.
- if (assocType)
- return updateNestedTypeForConformance(assocType, kind);
-
- return updateNestedTypeForConformance(concreteDecl, kind);
+ // Form the potential archetype.
+ return updateNestedTypeForConformance(bestType, kind);
}
PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance(
- PointerUnion<AssociatedTypeDecl *, TypeDecl *> type,
- ArchetypeResolutionKind kind) {
- auto *assocType = type.dyn_cast<AssociatedTypeDecl *>();
- auto *concreteDecl = type.dyn_cast<TypeDecl *>();
- if (!assocType && !concreteDecl)
- return nullptr;
+ TypeDecl *type,
+ ArchetypeResolutionKind kind) {
+ if (!type) return nullptr;
+
+ AssociatedTypeDecl *assocType = dyn_cast<AssociatedTypeDecl>(type);
+ TypeDecl *concreteDecl = assocType ? nullptr : type;
// If we were asked for a complete, well-formed archetype, make sure we
// process delayed requirements if anything changed.
@@ -3633,13 +3667,8 @@
auto parentRepPA = parentPA->getRepresentative();
if (parentPA == parentRepPA) return;
- PotentialArchetype *existingPA;
- if (auto assocType = nestedPA->getResolvedAssociatedType()) {
- existingPA = parentRepPA->getNestedType(assocType, *this);
- } else {
- existingPA = parentRepPA->getNestedType(nestedPA->getConcreteTypeDecl(),
- *this);
- }
+ PotentialArchetype *existingPA =
+ parentRepPA->getNestedType(nestedPA->getResolvedType(), *this);
auto sameNamedSource =
FloatingRequirementSource::forNestedTypeNameMatch(
@@ -3893,8 +3922,10 @@
UnresolvedHandlingKind unresolvedHandling) {
return addSameTypeRequirement(paOrT1, paOrT2, source, unresolvedHandling,
[&](Type type1, Type type2) {
- Diags.diagnose(source.getLoc(), diag::requires_same_concrete_type,
- type1, type2);
+ if (source.getLoc().isValid()) {
+ Diags.diagnose(source.getLoc(), diag::requires_same_concrete_type,
+ type1, type2);
+ }
});
}
@@ -4170,9 +4201,10 @@
firstType, secondType, source,
UnresolvedHandlingKind::GenerateConstraints,
[&](Type type1, Type type2) {
- if (source.getLoc().isValid())
+ if (source.getLoc().isValid()) {
Diags.diagnose(source.getLoc(), diag::requires_same_concrete_type,
type1, type2);
+ }
});
}
}
@@ -6293,21 +6325,23 @@
});
}
-GenericSignature *GenericSignatureBuilder::getGenericSignature() {
- assert(Impl->finalized && "Must finalize builder first");
+GenericSignature *GenericSignatureBuilder::computeGenericSignature(
+ SourceLoc loc,
+ bool allowConcreteGenericParams) && {
+ // Finalize the builder, producing any necessary diagnostics.
+ finalize(loc, Impl->GenericParams, allowConcreteGenericParams);
// Collect the requirements placed on the generic parameter types.
SmallVector<Requirement, 4> requirements;
collectRequirements(*this, Impl->GenericParams, requirements);
+ // Form the generic signature.
auto sig = GenericSignature::get(Impl->GenericParams, requirements);
- return sig;
-}
-GenericSignature *GenericSignatureBuilder::computeGenericSignature(
- SourceLoc loc,
- bool allowConcreteGenericParams) {
- finalize(loc, Impl->GenericParams, allowConcreteGenericParams);
- return getGenericSignature();
+ // Wipe out the internal state, ensuring that nobody uses this builder for
+ // anything more.
+ Impl.reset();
+
+ return sig;
}
diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp
index 16f22e8..66a8338 100644
--- a/lib/ClangImporter/ImportDecl.cpp
+++ b/lib/ClangImporter/ImportDecl.cpp
@@ -7654,7 +7654,7 @@
(void) result;
}
- return builder.computeGenericSignature(SourceLoc());
+ return std::move(builder).computeGenericSignature(SourceLoc());
}
// Calculate the generic environment from an imported generic param list.
diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp
index 829c219..9871d2f 100644
--- a/lib/SILGen/SILGenPoly.cpp
+++ b/lib/SILGen/SILGenPoly.cpp
@@ -2695,7 +2695,7 @@
builder.addRequirement(newRequirement, source, nullptr);
GenericSignature *genericSig =
- builder.computeGenericSignature(SourceLoc(),
+ std::move(builder).computeGenericSignature(SourceLoc(),
/*allowConcreteGenericParams=*/true);
genericEnv = genericSig->createGenericEnvironment(*mod);
diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp
index d841f25..b2fa942 100644
--- a/lib/SILOptimizer/Utils/Generics.cpp
+++ b/lib/SILOptimizer/Utils/Generics.cpp
@@ -800,7 +800,7 @@
}
auto NewGenSig =
- Builder.computeGenericSignature(SourceLoc(),
+ std::move(Builder).computeGenericSignature(SourceLoc(),
/*allowConcreteGenericParams=*/true);
auto NewGenEnv = NewGenSig->createGenericEnvironment(*M.getSwiftModule());
return { NewGenEnv, NewGenSig };
@@ -1490,7 +1490,7 @@
// Finalize the archetype builder.
auto GenSig =
- Builder.computeGenericSignature(SourceLoc(),
+ std::move(Builder).computeGenericSignature(SourceLoc(),
/*allowConcreteGenericParams=*/true);
auto GenEnv = GenSig->createGenericEnvironment(*M.getSwiftModule());
return { GenEnv, GenSig };
diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp
index 63d7375..072e9ae 100644
--- a/lib/Sema/TypeCheckAttr.cpp
+++ b/lib/Sema/TypeCheckAttr.cpp
@@ -1851,7 +1851,8 @@
Builder.addRequirement(&req, DC->getParentModule());
// Check the result.
- (void)Builder.computeGenericSignature(attr->getLocation(),
+ (void)std::move(Builder).computeGenericSignature(
+ attr->getLocation(),
/*allowConcreteGenericParams=*/true);
}
diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp
index 949f618..25b90cd 100644
--- a/lib/Sema/TypeCheckGeneric.cpp
+++ b/lib/Sema/TypeCheckGeneric.cpp
@@ -136,20 +136,19 @@
DeclContext *DC,
SourceRange baseRange,
ComponentIdentTypeRepr *ref) {
- // Resolve the base to a potential archetype.
- auto basePA =
- builder.resolveArchetype(baseTy,
- ArchetypeResolutionKind::CompleteWellFormed);
- assert(basePA && "Missing potential archetype for base");
+ auto baseEquivClass =
+ builder.resolveEquivalenceClass(
+ baseTy,
+ ArchetypeResolutionKind::CompleteWellFormed);
+ assert(baseEquivClass && "Unknown base type?");
- // Retrieve the potential archetype for the nested type.
- auto nestedPA =
- basePA->getNestedType(ref->getIdentifier(),
- ArchetypeResolutionKind::CompleteWellFormed,
- builder);
-
- // If there was no such nested type, produce an error.
- if (!nestedPA) {
+ // Look for a nested type with the given name.
+ if (auto nestedType =
+ baseEquivClass->lookupNestedType(ref->getIdentifier())) {
+ // Record the type we found.
+ ref->setValue(nestedType, nullptr);
+ } else {
+ // Resolve the base to a potential archetype.
// Perform typo correction.
LookupResult corrections;
tc.performTypoCorrection(DC, DeclRefKind::Ordinary,
@@ -189,11 +188,6 @@
// Correct to the single type result.
ref->overwriteIdentifier(singleType->getBaseName().getIdentifier());
ref->setValue(singleType, nullptr);
- } else if (auto assocType = nestedPA->getResolvedAssociatedType()) {
- ref->setValue(assocType, nullptr);
- } else {
- assert(nestedPA->getConcreteTypeDecl());
- ref->setValue(nestedPA->getConcreteTypeDecl(), nullptr);
}
// If the nested type has been resolved to an associated type, use it.
@@ -217,7 +211,7 @@
return concrete->getDeclaredInterfaceType().subst(subMap);
}
- if (auto superclass = basePA->getSuperclass()) {
+ if (auto superclass = baseEquivClass->superclass) {
return superclass->getTypeOfMember(
DC->getParentModule(), concrete,
concrete->getDeclaredInterfaceType());
@@ -752,13 +746,6 @@
if (auto gp = func->getGenericParams()) {
prepareGenericParamList(gp, func);
- // Collect the generic parameters.
- SmallVector<GenericTypeParamType *, 4> allGenericParams;
- if (auto parentSig = func->getDeclContext()->getGenericSignatureOfContext())
- allGenericParams.append(parentSig->getGenericParams().begin(),
- parentSig->getGenericParams().end());
- addGenericParamTypes(gp, allGenericParams);
-
// Create the generic signature builder.
GenericSignatureBuilder builder(Context, LookUpConformance(*this, func));
@@ -768,8 +755,9 @@
if (checkGenericFuncSignature(*this, &builder, func, dependentResolver))
invalid = true;
- // Finalize the generic requirements.
- (void)builder.finalize(func->getLoc(), allGenericParams);
+ // The generic function signature is complete and well-formed. Determine
+ // the type of the generic function.
+ sig = std::move(builder).computeGenericSignature(func->getLoc());
// The generic signature builder now has all of the requirements, although
// there might still be errors that have not yet been diagnosed. Revert the
@@ -778,16 +766,10 @@
if (gp)
revertGenericParamList(gp);
- // The generic function signature is complete and well-formed. Determine
- // the type of the generic function.
- sig = builder.getGenericSignature();
-
- // Debugging of the generic signature builder and generic signature
- // generation.
+ // Debugging of the generic signature.
if (Context.LangOpts.DebugGenericSignatures) {
func->dumpRef(llvm::errs());
llvm::errs() << "\n";
- builder.dump(llvm::errs());
llvm::errs() << "Generic signature: ";
sig->print(llvm::errs());
llvm::errs() << "\n";
@@ -987,15 +969,9 @@
if (auto *gp = subscript->getGenericParams()) {
prepareGenericParamList(gp, subscript);
- // Collect the generic parameters.
- SmallVector<GenericTypeParamType *, 4> allGenericParams;
- if (auto parentSig = subscript->getDeclContext()->getGenericSignatureOfContext())
- allGenericParams.append(parentSig->getGenericParams().begin(),
- parentSig->getGenericParams().end());
- addGenericParamTypes(gp, allGenericParams);
-
// Create the generic signature builder.
- GenericSignatureBuilder builder(Context, LookUpConformance(*this, subscript));
+ GenericSignatureBuilder builder(Context,
+ LookUpConformance(*this, subscript));
// Type check the function declaration, treating all generic type
// parameters as dependent, unresolved.
@@ -1004,8 +980,9 @@
dependentResolver))
invalid = true;
- // Finalize the generic requirements.
- (void)builder.finalize(subscript->getLoc(), allGenericParams);
+ // The generic subscript signature is complete and well-formed. Determine
+ // the type of the generic subscript.
+ sig = std::move(builder).computeGenericSignature(subscript->getLoc());
// The generic signature builder now has all of the requirements, although
// there might still be errors that have not yet been diagnosed. Revert the
@@ -1013,16 +990,10 @@
revertGenericSubscriptSignature(subscript);
revertGenericParamList(gp);
- // The generic subscript signature is complete and well-formed. Determine
- // the type of the generic subscript.
- sig = builder.getGenericSignature();
-
- // Debugging of the generic signature builder and generic signature
- // generation.
+ // Debugging of generic signature generation.
if (Context.LangOpts.DebugGenericSignatures) {
subscript->dumpRef(llvm::errs());
llvm::errs() << "\n";
- builder.dump(llvm::errs());
llvm::errs() << "Generic signature: ";
sig->print(llvm::errs());
llvm::errs() << "\n";
@@ -1148,10 +1119,10 @@
/// Perform any necessary requirement inference.
inferRequirements(builder);
- // Finalize the generic requirements.
- (void)builder.finalize(genericParams->getSourceRange().Start,
- allGenericParams,
- allowConcreteGenericParams);
+ // Record the generic type parameter types and the requirements.
+ sig = std::move(builder).computeGenericSignature(
+ genericParams->getSourceRange().Start,
+ allowConcreteGenericParams);
// The generic signature builder now has all of the requirements, although
// there might still be errors that have not yet been diagnosed. Revert the
@@ -1165,15 +1136,11 @@
revertGenericParamList(genericParams);
}
- // Record the generic type parameter types and the requirements.
- sig = builder.getGenericSignature();
-
// Debugging of the generic signature builder and generic signature
// generation.
if (Context.LangOpts.DebugGenericSignatures) {
dc->printContext(llvm::errs());
llvm::errs() << "\n";
- builder.dump(llvm::errs());
llvm::errs() << "Generic signature: ";
sig->print(llvm::errs());
llvm::errs() << "\n";
diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp
index d730a4a..686557d 100644
--- a/lib/Sema/TypeCheckProtocol.cpp
+++ b/lib/Sema/TypeCheckProtocol.cpp
@@ -1156,7 +1156,8 @@
// Produce the generic signature and environment.
// FIXME: Pass in a source location for the conformance, perhaps? It seems
// like this could fail.
- syntheticSignature = builder.computeGenericSignature(SourceLoc());
+ syntheticSignature =
+ std::move(builder).computeGenericSignature(SourceLoc());
syntheticEnvironment = syntheticSignature->createGenericEnvironment(
*conformanceDC->getParentModule());
}
diff --git a/test/Generics/associated_type_typo.swift b/test/Generics/associated_type_typo.swift
index f023418..4ac5b86 100644
--- a/test/Generics/associated_type_typo.swift
+++ b/test/Generics/associated_type_typo.swift
@@ -34,13 +34,6 @@
// expected-error@+1{{'T' does not have a member type named 'Assocp2'; did you mean 'AssocP2'?}}{{39-46=AssocP2}}
func typoAssoc4<T : P2>(_: T) where T.Assocp2.assoc : P3 {}
-
-// CHECK-GENERIC-LABEL: .typoAssoc4@
-// CHECK-GENERIC-NEXT: Requirements:
-// CHECK-GENERIC-NEXT: τ_0_0 : P2 [τ_0_0: Explicit @ {{.*}}:21]
-// CHECK-GENERIC-NEXT: τ_0_0[.P2].AssocP2 : P1 [τ_0_0: Explicit @ {{.*}}:21 -> Protocol requirement (via Self.AssocP2 in P2)
-// CHECK-GENERIC-NEXT: Potential archetypes
-
// <rdar://problem/19620340>
func typoFunc1<T : P1>(x: TypoType) { // expected-error{{use of undeclared type 'TypoType'}}
diff --git a/test/Generics/protocol_type_aliases.swift b/test/Generics/protocol_type_aliases.swift
index afb2661..9c083d4 100644
--- a/test/Generics/protocol_type_aliases.swift
+++ b/test/Generics/protocol_type_aliases.swift
@@ -14,10 +14,6 @@
}
// CHECK-LABEL: .requirementOnNestedTypeAlias@
-// CHECK-NEXT: Requirements:
-// CHECK-NEXT: τ_0_0 : Q [τ_0_0: Explicit @ 22:51]
-// CHECK-NEXT: τ_0_0[.Q].B : P [τ_0_0: Explicit @ 22:51 -> Protocol requirement (via Self.B in Q)
-// CHECK-NEXT: τ_0_0[.Q].B[.P].A == Int [τ_0_0[.Q].B[.P].X: Explicit @ 22:62]
// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : Q, τ_0_0.B.A == Int>
func requirementOnNestedTypeAlias<T>(_: T) where T: Q, T.B.X == Int {}
@@ -33,20 +29,10 @@
}
// CHECK-LABEL: .requirementOnConcreteNestedTypeAlias@
-// CHECK-NEXT: Requirements:
-// CHECK-NEXT: τ_0_0 : Q2 [τ_0_0: Explicit @ 42:59]
-// CHECK-NEXT: τ_0_0[.Q2].B : P2 [τ_0_0: Explicit @ 42:59 -> Protocol requirement (via Self.B in Q2)
-// CHECK-NEXT: τ_0_0[.Q2].C == S<T.B.A> [τ_0_0[.Q2].C: Explicit]
-// CHECK-NEXT: τ_0_0[.Q2].B[.P2].X == S<T.B.A> [τ_0_0[.Q2].B[.P2].X: Concrete type binding]
// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : Q2, τ_0_0.C == S<τ_0_0.B.A>>
func requirementOnConcreteNestedTypeAlias<T>(_: T) where T: Q2, T.C == T.B.X {}
// CHECK-LABEL: .concreteRequirementOnConcreteNestedTypeAlias@
-// CHECK-NEXT: Requirements:
-// CHECK-NEXT: τ_0_0 : Q2 [τ_0_0: Explicit @ 51:67]
-// CHECK-NEXT: τ_0_0[.Q2].B : P2 [τ_0_0: Explicit @ 51:67 -> Protocol requirement (via Self.B in Q2)
-// CHECK-NEXT: τ_0_0[.Q2].C == τ_0_0[.Q2].B[.P2].A [τ_0_0[.Q2].C: Explicit]
-// CHECK-NEXT: τ_0_0[.Q2].B[.P2].X == S<T.B.A> [τ_0_0[.Q2].B[.P2].X: Concrete type binding]
// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : Q2, τ_0_0.C == τ_0_0.B.A>
func concreteRequirementOnConcreteNestedTypeAlias<T>(_: T) where T: Q2, S<T.C> == T.B.X {}
diff --git a/test/Generics/requirement_inference.swift b/test/Generics/requirement_inference.swift
index ac124ae..391c9b4 100644
--- a/test/Generics/requirement_inference.swift
+++ b/test/Generics/requirement_inference.swift
@@ -72,16 +72,14 @@
struct V<T : Canidae> {}
// CHECK-LABEL: .inferSuperclassRequirement1@
-// CHECK-NEXT: Requirements:
-// CHECK-NEXT: τ_0_0 : Canidae
+// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : Canidae>
func inferSuperclassRequirement1<T : Carnivora>(
_ v: V<T>) {}
// expected-warning@-2{{redundant superclass constraint 'T' : 'Carnivora'}}
// expected-note@-2{{superclass constraint 'T' : 'Canidae' inferred from type here}}
// CHECK-LABEL: .inferSuperclassRequirement2@
-// CHECK-NEXT: Requirements:
-// CHECK-NEXT: τ_0_0 : Canidae
+// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : Canidae>
func inferSuperclassRequirement2<T : Canidae>(_ v: U<T>) {}
// ----------------------------------------------------------------------------
@@ -110,33 +108,17 @@
struct Model_P3_P4_Eq<T : P3, U : P4> where T.P3Assoc == U.P4Assoc {}
-// CHECK-LABEL: .inferSameType1@
-// CHECK-NEXT: Requirements:
-// CHECK-NEXT: τ_0_0 : P3 [τ_0_0: Inferred @ {{.*}}:32]
-// CHECK-NEXT: τ_0_1 : P4 [τ_0_1: Inferred @ {{.*}}:32]
-// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P1 [τ_0_1: Inferred @ {{.*}}:32 -> Protocol requirement (via Self.P4Assoc in P4)
-// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P2 [τ_0_0: Inferred @ {{.*}}:32 -> Protocol requirement (via Self.P3Assoc in P3)
-// FIXME: τ_0_0[.P3].P3Assoc == τ_0_1[.P4].P4Assoc [τ_0_0: Inferred]
-func inferSameType1<T, U>(_ x: Model_P3_P4_Eq<T, U>) { }
+func inferSameType1<T, U>(_ x: Model_P3_P4_Eq<T, U>) {
+ let u: U.P4Assoc? = nil
+ let _: T.P3Assoc? = u!
+}
-// CHECK-LABEL: .inferSameType2@
-// CHECK-NEXT: Requirements:
-// CHECK-NEXT: τ_0_0 : P3 [τ_0_0: Explicit @ {{.*}}:25]
-// CHECK-NEXT: τ_0_1 : P4 [τ_0_1: Explicit @ {{.*}}:33]
-// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P1 [τ_0_1: Explicit @ {{.*}}:33 -> Protocol requirement (via Self.P4Assoc in P4)
-// CHECK-NEXT: τ_0_0[.P3].P3Assoc : P2 [τ_0_0: Explicit @ {{.*}}:25 -> Protocol requirement (via Self.P3Assoc in P3)
-// CHECK-NEXT: τ_0_0[.P3].P3Assoc == τ_0_1[.P4].P4Assoc [τ_0_0[.P3].P3Assoc: Explicit]
func inferSameType2<T : P3, U : P4>(_: T, _: U) where U.P4Assoc : P2, T.P3Assoc == U.P4Assoc {}
// expected-warning@-1{{redundant conformance constraint 'T.P3Assoc': 'P2'}}
// expected-note@-2{{conformance constraint 'T.P3Assoc': 'P2' implied here}}
-// CHECK-LABEL: .inferSameType3@
-// CHECK-NEXT: Requirements:
-// CHECK-NEXT: τ_0_0 : PCommonAssoc1 [τ_0_0: Explicit @ {{.*}}:25]
-// CHECK-NEXT: τ_0_0 : PCommonAssoc2 [τ_0_0: Explicit @ {{.*}}:74]
-// CHECK-NEXT: τ_0_0[.PCommonAssoc1].CommonAssoc : P1 [τ_0_0[.PCommonAssoc1].CommonAssoc: Explicit @ {{.*}}:66]
-// CHECK-NEXT: Potential archetypes
-func inferSameType3<T : PCommonAssoc1>(_: T) where T.CommonAssoc : P1, T : PCommonAssoc2 {}
+func inferSameType3<T : PCommonAssoc1>(_: T) where T.CommonAssoc : P1, T : PCommonAssoc2 {
+}
protocol P5 {
associatedtype Element
diff --git a/test/Generics/superclass_constraint.swift b/test/Generics/superclass_constraint.swift
index d02efc5..b27d7af 100644
--- a/test/Generics/superclass_constraint.swift
+++ b/test/Generics/superclass_constraint.swift
@@ -67,10 +67,6 @@
}
// CHECK: superclassConformance1
-// CHECK: Requirements:
-// CHECK-NEXT: τ_0_0 : C [τ_0_0: Explicit @ {{.*}}:11]
-// CHECK-NEXT: τ_0_0 : _NativeClass [τ_0_0: Explicit @ {{.*}}:11 -> Derived]
-// CHECK-NEXT: τ_0_0 : P3 [τ_0_0: Explicit @ {{.*}}:11 -> Superclass (C: P3)]
// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C>
func superclassConformance1<T>(t: T)
where T : C, // expected-note{{conformance constraint 'T': 'P3' implied here}}
@@ -79,10 +75,6 @@
// CHECK: superclassConformance2
-// CHECK: Requirements:
-// CHECK-NEXT: τ_0_0 : C [τ_0_0: Explicit @ {{.*}}:11]
-// CHECK-NEXT: τ_0_0 : _NativeClass [τ_0_0: Explicit @ {{.*}}:11 -> Derived]
-// CHECK-NEXT: τ_0_0 : P3 [τ_0_0: Explicit @ {{.*}}:11 -> Superclass (C: P3)]
// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C>
func superclassConformance2<T>(t: T)
where T : C, // expected-note{{conformance constraint 'T': 'P3' implied here}}
@@ -93,10 +85,6 @@
class C2 : C, P4 { }
// CHECK: superclassConformance3
-// CHECK: Requirements:
-// CHECK-NEXT: τ_0_0 : C2 [τ_0_0: Explicit @ {{.*}}:61]
-// CHECK-NEXT: τ_0_0 : _NativeClass [τ_0_0: Explicit @ {{.*}}:46 -> Derived]
-// CHECK-NEXT: τ_0_0 : P4 [τ_0_0: Explicit @ {{.*}}:61 -> Superclass (C2: P4)]
// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C2>
func superclassConformance3<T>(t: T) where T : C, T : P4, T : C2 {}
// expected-warning@-1{{redundant superclass constraint 'T' : 'C'}}
diff --git a/test/decl/protocol/recursive_requirement.swift b/test/decl/protocol/recursive_requirement.swift
index 736d2af..30cd1a0 100644
--- a/test/decl/protocol/recursive_requirement.swift
+++ b/test/decl/protocol/recursive_requirement.swift
@@ -76,13 +76,14 @@
associatedtype Delta: Alpha
}
-// FIXME: Redundancy diagnostics are odd here.
+// FIXME: Redundancy diagnostics are an indication that we're getting
+// the minimization wrong. The errors prove it :D
struct Epsilon<T: Alpha, // expected-note{{conformance constraint 'U': 'Gamma' implied here}}
// expected-warning@-1{{redundant conformance constraint 'T': 'Alpha'}}
U: Gamma> // expected-warning{{redundant conformance constraint 'U': 'Gamma'}}
// expected-note@-1{{conformance constraint 'T': 'Alpha' implied here}}
- where T.Beta == U,
- U.Delta == T {}
+ where T.Beta == U, // expected-error{{'Beta' is not a member type of 'T'}}
+ U.Delta == T {} // expected-error{{'Delta' is not a member type of 'U'}}
// -----
diff --git a/validation-test/compiler_crashers/28816-unreachable-executed-at-swift-lib-sema-typecheckgeneric-cpp-214.swift b/validation-test/compiler_crashers_fixed/28816-unreachable-executed-at-swift-lib-sema-typecheckgeneric-cpp-214.swift
similarity index 88%
rename from validation-test/compiler_crashers/28816-unreachable-executed-at-swift-lib-sema-typecheckgeneric-cpp-214.swift
rename to validation-test/compiler_crashers_fixed/28816-unreachable-executed-at-swift-lib-sema-typecheckgeneric-cpp-214.swift
index 1c78fe4..02b9326 100644
--- a/validation-test/compiler_crashers/28816-unreachable-executed-at-swift-lib-sema-typecheckgeneric-cpp-214.swift
+++ b/validation-test/compiler_crashers_fixed/28816-unreachable-executed-at-swift-lib-sema-typecheckgeneric-cpp-214.swift
@@ -5,6 +5,6 @@
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
-// RUN: not --crash %target-swift-frontend %s -emit-ir
+// RUN: not %target-swift-frontend %s -emit-ir
protocol b{{}{}class a{{}class A}{}typealias a
init(t:Self.a.a.a