Merge pull request #19601 from slavapestov/fewer-gsbs-2
Create fewer GenericSignatureBuilders, part 2
diff --git a/include/swift/AST/GenericSignature.h b/include/swift/AST/GenericSignature.h
index 47b4198..db19336 100644
--- a/include/swift/AST/GenericSignature.h
+++ b/include/swift/AST/GenericSignature.h
@@ -190,9 +190,10 @@
Optional<ProtocolConformanceRef>
lookupConformance(CanType depTy, ProtocolDecl *proto) const;
- /// Return a vector of all generic parameters that are not subject to
- /// a concrete same-type constraint.
- SmallVector<GenericTypeParamType *, 2> getSubstitutableParams() const;
+ /// Iterate over all generic parameters, passing a flag to the callback
+ /// indicating if the generic parameter is canonical or not.
+ void forEachParam(
+ llvm::function_ref<void(GenericTypeParamType *, bool)> callback) const;
/// Check if the generic signature makes all generic parameters
/// concrete.
diff --git a/include/swift/AST/ProtocolConformance.h b/include/swift/AST/ProtocolConformance.h
index 22aabc2..dd28931 100644
--- a/include/swift/AST/ProtocolConformance.h
+++ b/include/swift/AST/ProtocolConformance.h
@@ -415,7 +415,6 @@
{
assert(!conformingType->hasArchetype() &&
"ProtocolConformances should store interface types");
- differenceAndStoreConditionalRequirements();
}
NormalProtocolConformance(Type conformingType,
@@ -428,7 +427,6 @@
{
assert(!conformingType->hasArchetype() &&
"ProtocolConformances should store interface types");
- differenceAndStoreConditionalRequirements();
}
void resolveLazyInfo() const;
diff --git a/include/swift/AST/Witness.h b/include/swift/AST/Witness.h
index 302ad86..0721398 100644
--- a/include/swift/AST/Witness.h
+++ b/include/swift/AST/Witness.h
@@ -117,6 +117,15 @@
return Witness(requirement);
}
+ /// Create a witness for the given requirement.
+ ///
+ /// Deserialized witnesses do not have a synthetic environment.
+ static Witness forDeserialized(ValueDecl *decl,
+ SubstitutionMap substitutions) {
+ // TODO: It's probably a good idea to have a separate 'deserialized' bit.
+ return Witness(decl, substitutions, nullptr, SubstitutionMap());
+ }
+
/// Create a witness that requires substitutions.
///
/// \param decl The declaration for the witness.
diff --git a/include/swift/SIL/TypeSubstCloner.h b/include/swift/SIL/TypeSubstCloner.h
index d87b92a..0a02ba0 100644
--- a/include/swift/SIL/TypeSubstCloner.h
+++ b/include/swift/SIL/TypeSubstCloner.h
@@ -297,12 +297,15 @@
if (SubsMap.empty())
return false;
- for (auto ParamType : Sig->getSubstitutableParams()) {
+ bool Result = false;
+ Sig->forEachParam([&](GenericTypeParamType *ParamType, bool Canonical) {
+ if (!Canonical)
+ return;
if (!Type(ParamType).subst(SubsMap)->isEqual(ParamType))
- return true;
- }
+ Result = true;
+ });
- return false;
+ return Result;
}
enum { ForInlining = true };
diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h
index 5fb65dd..9b69765 100644
--- a/include/swift/Serialization/ModuleFormat.h
+++ b/include/swift/Serialization/ModuleFormat.h
@@ -55,7 +55,7 @@
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
/// Don't worry about adhering to the 80-column limit for this line.
-const uint16_t VERSION_MINOR = 449; // Last change: serialize @_implements names
+const uint16_t VERSION_MINOR = 450; // Last change: don't serialize requirement environment
using DeclIDField = BCFixed<31>;
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 032db0f..b0e5469 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -4384,14 +4384,15 @@
// Profile those replacement types that corresponding to canonical generic
// parameters within the generic signature.
id.AddInteger(replacementTypes.size());
- auto genericParams = genericSig->getGenericParams();
- for (unsigned i : indices(genericParams)) {
- auto gp = genericParams[i];
- if (genericSig->isCanonicalTypeInContext(gp->getCanonicalType()))
+
+ unsigned i = 0;
+ genericSig->forEachParam([&](GenericTypeParamType *gp, bool canonical) {
+ if (canonical)
id.AddPointer(replacementTypes[i].getPointer());
else
id.AddPointer(nullptr);
- }
+ i++;
+ });
// Conformances.
id.AddInteger(conformances.size());
diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp
index cd6b5b4..c1e71d0 100644
--- a/lib/AST/GenericSignature.cpp
+++ b/lib/AST/GenericSignature.cpp
@@ -97,45 +97,42 @@
return params;
}
-
-SmallVector<GenericTypeParamType *, 2>
-GenericSignature::getSubstitutableParams() const {
+void GenericSignature::forEachParam(
+ llvm::function_ref<void(GenericTypeParamType *, bool)> callback) const {
// Figure out which generic parameters are concrete or same-typed to another
- // generic parameter.
+ // type parameter.
auto genericParams = getGenericParams();
- auto genericParamsAreNotSubstitutable =
- SmallVector<bool, 4>(genericParams.size(), false);
+ auto genericParamsAreCanonical =
+ SmallVector<bool, 4>(genericParams.size(), true);
+
for (auto req : getRequirements()) {
if (req.getKind() != RequirementKind::SameType) continue;
GenericTypeParamType *gp;
if (auto secondGP = req.getSecondType()->getAs<GenericTypeParamType>()) {
- // If two generic parameters are same-typed, then the left-hand one
- // is canonical.
+ // If two generic parameters are same-typed, then the right-hand one
+ // is non-canonical.
+ assert(req.getFirstType()->is<GenericTypeParamType>());
gp = secondGP;
} else {
- // If an associated type is same-typed, it doesn't constrain the generic
- // parameter itself.
- if (req.getSecondType()->isTypeParameter()) continue;
-
- // Otherwise, the generic parameter is concrete.
+ // Otherwise, the right-hand side is an associated type or concrete type,
+ // and the left-hand one is non-canonical.
gp = req.getFirstType()->getAs<GenericTypeParamType>();
if (!gp) continue;
+
+ // If an associated type is same-typed, it doesn't constrain the generic
+ // parameter itself. That is, if T == U.Foo, then T is canonical, whereas
+ // U.Foo is not.
+ if (req.getSecondType()->isTypeParameter()) continue;
}
unsigned index = GenericParamKey(gp).findIndexIn(genericParams);
- genericParamsAreNotSubstitutable[index] = true;
+ genericParamsAreCanonical[index] = false;
}
- // Collect the generic parameters that are substitutable.
- SmallVector<GenericTypeParamType *, 2> result;
- for (auto index : indices(genericParams)) {
- auto gp = genericParams[index];
- if (!genericParamsAreNotSubstitutable[index])
- result.push_back(gp);
- }
-
- return result;
+ // Call the callback with each parameter and the result of the above analysis.
+ for (auto index : indices(genericParams))
+ callback(genericParams[index], genericParamsAreCanonical[index]);
}
bool GenericSignature::areAllParamsConcrete() const {
diff --git a/lib/AST/ProtocolConformance.cpp b/lib/AST/ProtocolConformance.cpp
index 507366a..f2f03c6 100644
--- a/lib/AST/ProtocolConformance.cpp
+++ b/lib/AST/ProtocolConformance.cpp
@@ -886,7 +886,6 @@
GenericSubstitutions(substitutions)
{
assert(genericConformance->getKind() != ProtocolConformanceKind::Specialized);
- computeConditionalRequirements();
}
void SpecializedProtocolConformance::computeConditionalRequirements() const {
diff --git a/lib/AST/SubstitutionMap.cpp b/lib/AST/SubstitutionMap.cpp
index 41a6c17..c81100a 100644
--- a/lib/AST/SubstitutionMap.cpp
+++ b/lib/AST/SubstitutionMap.cpp
@@ -200,18 +200,19 @@
// Form the replacement types.
SmallVector<Type, 4> replacementTypes;
replacementTypes.reserve(genericSig->getGenericParams().size());
- for (auto gp : genericSig->getGenericParams()) {
+
+ genericSig->forEachParam([&](GenericTypeParamType *gp, bool canonical) {
// Don't eagerly form replacements for non-canonical generic parameters.
- if (!genericSig->isCanonicalTypeInContext(gp->getCanonicalType())) {
+ if (!canonical) {
replacementTypes.push_back(Type());
- continue;
+ return;
}
// Record the replacement.
Type replacement = Type(gp).subst(subs, lookupConformance,
SubstFlags::UseErrorType);
replacementTypes.push_back(replacement);
- }
+ });
// Form the stored conformances.
SmallVector<ProtocolConformanceRef, 4> conformances;
@@ -318,6 +319,20 @@
if (!type->isTypeParameter())
return None;
+ auto genericSig = getGenericSignature();
+
+ // Fast path
+ unsigned index = 0;
+ for (auto reqt : genericSig->getRequirements()) {
+ if (reqt.getKind() == RequirementKind::Conformance) {
+ if (reqt.getFirstType()->isEqual(type) &&
+ reqt.getSecondType()->isEqual(proto->getDeclaredType()))
+ return getConformances()[index];
+
+ index++;
+ }
+ }
+
// Retrieve the starting conformance from the conformance map.
auto getInitialConformance =
[&](Type type, ProtocolDecl *proto) -> Optional<ProtocolConformanceRef> {
@@ -338,8 +353,6 @@
return None;
};
- auto genericSig = getGenericSignature();
-
// If the type doesn't conform to this protocol, the result isn't formed
// from these requirements.
if (!genericSig->conformsToProtocol(type, proto)) {
diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp
index c7d8caa..953d72f 100644
--- a/lib/IRGen/GenMeta.cpp
+++ b/lib/IRGen/GenMeta.cpp
@@ -313,15 +313,15 @@
GenericSignature *sig = asImpl().getGenericSignature();
assert(sig);
auto canSig = sig->getCanonicalSignature();
-
- for (auto param : canSig->getGenericParams()) {
+
+ canSig->forEachParam([&](GenericTypeParamType *param, bool canonical) {
// Currently, there are only type parameters. The parameter is a key
// argument if it's canonical in its generic context.
asImpl().addGenericParameter(GenericParamKind::Type,
- /*key argument*/ canSig->isCanonicalTypeInContext(param),
- /*extra argument*/ false);
- }
-
+ /*key argument*/ canonical,
+ /*extra argument*/ false);
+ });
+
// Pad the structure up to four bytes for the following requirements.
unsigned padding = (unsigned) -canSig->getGenericParams().size() & 3;
for (unsigned i = 0; i < padding; ++i)
diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp
index 9a6883a..f35622a 100644
--- a/lib/IRGen/GenProto.cpp
+++ b/lib/IRGen/GenProto.cpp
@@ -238,9 +238,10 @@
if (!signature) return;
// Get all of the type metadata.
- for (auto gp : signature->getSubstitutableParams()) {
- callback({CanType(gp), nullptr});
- }
+ signature->forEachParam([&](GenericTypeParamType *gp, bool canonical) {
+ if (canonical)
+ callback({CanType(gp), nullptr});
+ });
// Get the protocol conformances.
for (auto &reqt : signature->getRequirements()) {
diff --git a/lib/RemoteAST/RemoteAST.cpp b/lib/RemoteAST/RemoteAST.cpp
index 6c69919..7a831fa 100644
--- a/lib/RemoteAST/RemoteAST.cpp
+++ b/lib/RemoteAST/RemoteAST.cpp
@@ -178,7 +178,12 @@
// Build a SubstitutionMap.
auto *genericSig = decl->getGenericSignature();
- auto genericParams = genericSig->getSubstitutableParams();
+
+ SmallVector<GenericTypeParamType *, 4> genericParams;
+ genericSig->forEachParam([&](GenericTypeParamType *gp, bool canonical) {
+ if (canonical)
+ genericParams.push_back(gp);
+ });
if (genericParams.size() != args.size())
return Type();
diff --git a/lib/SILOptimizer/IPO/EagerSpecializer.cpp b/lib/SILOptimizer/IPO/EagerSpecializer.cpp
index ef533dd..0cdf70d 100644
--- a/lib/SILOptimizer/IPO/EagerSpecializer.cpp
+++ b/lib/SILOptimizer/IPO/EagerSpecializer.cpp
@@ -347,7 +347,11 @@
auto GenericSig =
GenericFunc->getLoweredFunctionType()->getGenericSignature();
auto SubMap = ReInfo.getClonerParamSubstitutionMap();
- for (auto ParamTy : GenericSig->getSubstitutableParams()) {
+
+ GenericSig->forEachParam([&](GenericTypeParamType *ParamTy, bool Canonical) {
+ if (!Canonical)
+ return;
+
auto Replacement = Type(ParamTy).subst(SubMap);
assert(!Replacement->hasTypeParameter());
@@ -368,7 +372,8 @@
Replacement, LayoutInfo);
}
}
- }
+ });
+
static_cast<void>(FailedTypeCheckBB);
if (OldReturnBB == &EntryBB) {
diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp
index a586a0a..8622424 100644
--- a/lib/SILOptimizer/Utils/Generics.cpp
+++ b/lib/SILOptimizer/Utils/Generics.cpp
@@ -434,7 +434,11 @@
bool HasConcreteGenericParams = false;
bool HasNonArchetypeGenericParams = false;
HasUnboundGenericParams = false;
- for (auto GP : CalleeGenericSig->getSubstitutableParams()) {
+
+ CalleeGenericSig->forEachParam([&](GenericTypeParamType *GP, bool Canonical) {
+ if (!Canonical)
+ return;
+
// Check only the substitutions for the generic parameters.
// Ignore any dependent types, etc.
auto Replacement = Type(GP).subst(CalleeParamSubMap);
@@ -458,11 +462,10 @@
HasNonArchetypeGenericParams = true;
}
}
- continue;
+ } else {
+ HasConcreteGenericParams = true;
}
-
- HasConcreteGenericParams = true;
- }
+ });
if (HasUnboundGenericParams) {
// Bail if we cannot specialize generic substitutions, but all substitutions
@@ -1561,14 +1564,16 @@
// Simply create a set of same-type requirements based on concrete
// substitutions.
SmallVector<Requirement, 4> Requirements;
- for (auto GP : CalleeGenericSig->getSubstitutableParams()) {
+ CalleeGenericSig->forEachParam([&](GenericTypeParamType *GP, bool Canonical) {
+ if (!Canonical)
+ return;
auto Replacement = Type(GP).subst(CalleeInterfaceToCallerArchetypeMap);
if (Replacement->hasArchetype())
- continue;
+ return;
// Replacement is concrete. Add a same type requirement.
Requirement Req(RequirementKind::SameType, GP, Replacement);
Requirements.push_back(Req);
- }
+ });
// Create a new generic signature by taking the existing one
// and adding new requirements to it. No need to introduce
diff --git a/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp b/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp
index a8d9d99..80102db 100644
--- a/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp
+++ b/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp
@@ -625,10 +625,15 @@
static bool isCallerAndCalleeLayoutConstraintsCompatible(FullApplySite AI) {
SILFunction *Callee = AI.getReferencedFunction();
auto CalleeSig = Callee->getLoweredFunctionType()->getGenericSignature();
- auto SubstParams = CalleeSig->getSubstitutableParams();
auto AISubs = AI.getSubstitutionMap();
- for (auto idx : indices(SubstParams)) {
- auto Param = SubstParams[idx];
+
+ SmallVector<GenericTypeParamType *, 4> SubstParams;
+ CalleeSig->forEachParam([&](GenericTypeParamType *Param, bool Canonical) {
+ if (Canonical)
+ SubstParams.push_back(Param);
+ });
+
+ for (auto Param : SubstParams) {
// Map the parameter into context
auto ContextTy = Callee->mapTypeIntoContext(Param->getCanonicalType());
auto Archetype = ContextTy->getAs<ArchetypeType>();
diff --git a/lib/SILOptimizer/Utils/SpecializationMangler.cpp b/lib/SILOptimizer/Utils/SpecializationMangler.cpp
index aea7e04..03f5746 100644
--- a/lib/SILOptimizer/Utils/SpecializationMangler.cpp
+++ b/lib/SILOptimizer/Utils/SpecializationMangler.cpp
@@ -83,10 +83,12 @@
}
bool First = true;
- for (auto ParamType : Sig->getSubstitutableParams()) {
- appendType(Type(ParamType).subst(SubMap)->getCanonicalType());
- appendListSeparator(First);
- }
+ Sig->forEachParam([&](GenericTypeParamType *ParamType, bool Canonical) {
+ if (Canonical) {
+ appendType(Type(ParamType).subst(SubMap)->getCanonicalType());
+ appendListSeparator(First);
+ }
+ });
assert(!First && "no generic substitutions");
if (isInlined)
diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp
index 1814e55..7ac46ba 100644
--- a/lib/Sema/CSBindings.cpp
+++ b/lib/Sema/CSBindings.cpp
@@ -333,7 +333,7 @@
// should be allowed to escape. As a result we allow anything
// passed in to escape.
if (auto *fnTy = type->getAs<AnyFunctionType>())
- if (typeVar->getImpl().getArchetype() && !shouldAttemptFixes())
+ if (typeVar->getImpl().getGenericParameter() && !shouldAttemptFixes())
type = fnTy->withExtInfo(fnTy->getExtInfo().withNoEscape(false));
// Check whether we can perform this binding.
diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp
index e186492..912246d 100644
--- a/lib/Sema/CSDiag.cpp
+++ b/lib/Sema/CSDiag.cpp
@@ -472,15 +472,16 @@
/// true.
bool diagnoseAmbiguousMultiStatementClosure(ClosureExpr *closure);
- /// Check the associated constraint system to see if it has any archetypes
- /// not properly resolved or missing. If so, diagnose the problem with
- /// an error and return true.
- bool diagnoseArchetypeAmbiguity();
+ /// Check the associated constraint system to see if it has any opened generic
+ /// parameters that were not bound to a fixed type. If so, diagnose the
+ /// problem with an error and return true.
+ bool diagnoseAmbiguousGenericParameters();
- /// Emit an error message about an unbound generic parameter existing, and
- /// emit notes referring to the target of a diagnostic, e.g., the function
- /// or parameter being used.
- void diagnoseUnboundArchetype(ArchetypeType *archetype, Expr *anchor);
+ /// Emit an error message about an unbound generic parameter, and emit notes
+ /// referring to the target of a diagnostic, e.g., the function or parameter
+ /// being used.
+ void diagnoseAmbiguousGenericParameter(GenericTypeParamType *paramTy,
+ Expr *anchor);
/// Produce a diagnostic for a general member-lookup failure (irrespective of
/// the exact expression kind).
@@ -4687,9 +4688,12 @@
.getOldType()
->getWithoutSpecifierType();
- if (argType->is<ArchetypeType>()) {
- diagnoseUnboundArchetype(archetype, fnExpr);
- return true;
+ if (auto *archetype = argType->getAs<ArchetypeType>()) {
+ auto interfaceTy = archetype->getInterfaceType();
+ if (auto *paramTy = interfaceTy->getAs<GenericTypeParamType>()) {
+ diagnoseAmbiguousGenericParameter(paramTy, fnExpr);
+ return true;
+ }
}
if (isUnresolvedOrTypeVarType(argType) || argType->hasError())
@@ -7735,22 +7739,18 @@
diagnosis.diagnoseAmbiguity(expr);
}
-// FIXME: Instead of doing this, we should store the decl in the type
-// variable, or in the locator.
-static bool hasArchetype(const GenericTypeDecl *generic,
- ArchetypeType *archetype) {
- assert(!archetype->getOpenedExistentialType() &&
- !archetype->getParent());
-
- auto genericEnv = generic->getGenericEnvironment();
- if (!genericEnv)
+static bool hasGenericParameter(const GenericTypeDecl *generic,
+ GenericTypeParamType *paramTy) {
+ auto *decl = paramTy->getDecl();
+ if (!decl)
return false;
- return archetype->getGenericEnvironment() == genericEnv;
+ return decl->getDeclContext() == generic;
}
-static void noteArchetypeSource(const TypeLoc &loc, ArchetypeType *archetype,
- ConstraintSystem &cs) {
+static void noteGenericParameterSource(const TypeLoc &loc,
+ GenericTypeParamType *paramTy,
+ ConstraintSystem &cs) {
const GenericTypeDecl *FoundDecl = nullptr;
const ComponentIdentTypeRepr *FoundGenericTypeBase = nullptr;
@@ -7759,10 +7759,10 @@
struct FindGenericTypeDecl : public ASTWalker {
const GenericTypeDecl *FoundDecl = nullptr;
const ComponentIdentTypeRepr *FoundGenericTypeBase = nullptr;
- ArchetypeType *Archetype;
+ GenericTypeParamType *ParamTy;
- FindGenericTypeDecl(ArchetypeType *Archetype)
- : Archetype(Archetype) {}
+ FindGenericTypeDecl(GenericTypeParamType *ParamTy)
+ : ParamTy(ParamTy) {}
bool walkToTypeReprPre(TypeRepr *T) override {
// If we already emitted the note, we're done.
@@ -7771,7 +7771,7 @@
if (auto ident = dyn_cast<ComponentIdentTypeRepr>(T)) {
auto *generic =
dyn_cast_or_null<GenericTypeDecl>(ident->getBoundDecl());
- if (generic && hasArchetype(generic, Archetype)) {
+ if (generic && hasGenericParameter(generic, ParamTy)) {
FoundDecl = generic;
FoundGenericTypeBase = ident;
return false;
@@ -7780,7 +7780,7 @@
// Keep walking.
return true;
}
- } findGenericTypeDecl(archetype);
+ } findGenericTypeDecl(paramTy);
typerepr->walk(findGenericTypeDecl);
FoundDecl = findGenericTypeDecl.FoundDecl;
@@ -7791,7 +7791,7 @@
// type checked expression.
if (!FoundDecl) {
if (const GenericTypeDecl *generic = loc.getType()->getAnyGeneric())
- if (hasArchetype(generic, archetype))
+ if (hasGenericParameter(generic, paramTy))
FoundDecl = generic;
}
@@ -7804,7 +7804,7 @@
type = typeAlias->getUnboundGenericType();
else
type = FoundDecl->getDeclaredInterfaceType();
- tc.diagnose(FoundDecl, diag::archetype_declared_in_type, archetype, type);
+ tc.diagnose(FoundDecl, diag::archetype_declared_in_type, paramTy, type);
}
if (FoundGenericTypeBase && !isa<GenericIdentTypeRepr>(FoundGenericTypeBase)){
@@ -8065,25 +8065,23 @@
/// Check the associated constraint system to see if it has any archetypes
/// not properly resolved or missing. If so, diagnose the problem with
/// an error and return true.
-bool FailureDiagnosis::diagnoseArchetypeAmbiguity() {
- using Archetype = std::tuple<ArchetypeType *, ConstraintLocator *, unsigned>;
+bool FailureDiagnosis::diagnoseAmbiguousGenericParameters() {
+ using GenericParameter = std::tuple<GenericTypeParamType *,
+ ConstraintLocator *,
+ unsigned>;
- llvm::SmallVector<Archetype, 2> unboundParams;
- // Check out all of the type variables lurking in the system. If any are
- // unbound archetypes, then the problem is that it couldn't be resolved.
+ llvm::SmallVector<GenericParameter, 2> unboundParams;
+ // Check out all of the type variables lurking in the system. If any free
+ // type variables were created when opening generic parameters, diagnose
+ // that the generic parameter could not be inferred.
for (auto tv : CS.getTypeVariables()) {
auto &impl = tv->getImpl();
if (impl.hasRepresentativeOrFixed())
continue;
- // If this is a conversion to a type variable used to form an archetype,
- // Then diagnose this as a generic parameter that could not be resolved.
- auto archetype = impl.getArchetype();
-
- // Only diagnose archetypes that don't have a parent, i.e., ones
- // that correspond to generic parameters.
- if (!archetype || archetype->getParent())
+ auto *paramTy = impl.getGenericParameter();
+ if (!paramTy)
continue;
// Number of constraints related to particular unbound parameter
@@ -8117,22 +8115,22 @@
}
auto locator = impl.getLocator();
- unboundParams.push_back(
- std::make_tuple(archetype, locator, numConstraints));
+ unboundParams.emplace_back(paramTy, locator, numConstraints);
}
// We've found unbound generic parameters, let's diagnose
// based on the number of constraints each one is related to.
if (!unboundParams.empty()) {
- // Let's prioritize archetypes that don't have any constraints associated.
+ // Let's prioritize generic parameters that don't have any constraints
+ // associated.
std::stable_sort(unboundParams.begin(), unboundParams.end(),
- [](Archetype a, Archetype b) {
+ [](GenericParameter a, GenericParameter b) {
return std::get<2>(a) < std::get<2>(b);
});
auto param = unboundParams.front();
- diagnoseUnboundArchetype(std::get<0>(param),
- std::get<1>(param)->getAnchor());
+ diagnoseAmbiguousGenericParameter(std::get<0>(param),
+ std::get<1>(param)->getAnchor());
return true;
}
@@ -8142,18 +8140,19 @@
/// Emit an error message about an unbound generic parameter existing, and
/// emit notes referring to the target of a diagnostic, e.g., the function
/// or parameter being used.
-void FailureDiagnosis::diagnoseUnboundArchetype(ArchetypeType *archetype,
- Expr *anchor) {
+void FailureDiagnosis::
+diagnoseAmbiguousGenericParameter(GenericTypeParamType *paramTy,
+ Expr *anchor) {
auto &tc = CS.getTypeChecker();
- // The archetype may come from the explicit type in a cast expression.
+ // The generic parameter may come from the explicit type in a cast expression.
if (auto *ECE = dyn_cast_or_null<ExplicitCastExpr>(anchor)) {
tc.diagnose(ECE->getLoc(), diag::unbound_generic_parameter_cast,
- archetype, ECE->getCastTypeLoc().getType())
+ paramTy, ECE->getCastTypeLoc().getType())
.highlight(ECE->getCastTypeLoc().getSourceRange());
// Emit a note specifying where this came from, if we can find it.
- noteArchetypeSource(ECE->getCastTypeLoc(), archetype, CS);
+ noteGenericParameterSource(ECE->getCastTypeLoc(), paramTy, CS);
return;
}
@@ -8173,17 +8172,17 @@
// Otherwise, emit an error message on the expr we have, and emit a note
- // about where the archetype came from.
- tc.diagnose(expr->getLoc(), diag::unbound_generic_parameter, archetype);
+ // about where the generic parameter came from.
+ tc.diagnose(expr->getLoc(), diag::unbound_generic_parameter, paramTy);
// If we have an anchor, drill into it to emit a
- // "note: archetype declared here".
+ // "note: generic parameter declared here".
if (!anchor) return;
if (auto TE = dyn_cast<TypeExpr>(anchor)) {
// Emit a note specifying where this came from, if we can find it.
- noteArchetypeSource(TE->getTypeLoc(), archetype, CS);
+ noteGenericParameterSource(TE->getTypeLoc(), paramTy, CS);
return;
}
@@ -8232,8 +8231,8 @@
/// Emit an ambiguity diagnostic about the specified expression.
void FailureDiagnosis::diagnoseAmbiguity(Expr *E) {
// First, let's try to diagnose any problems related to ambiguous
- // archetypes (generic parameters) present in the constraint system.
- if (diagnoseArchetypeAmbiguity())
+ // generic parameters present in the constraint system.
+ if (diagnoseAmbiguousGenericParameters())
return;
// Unresolved/Anonymous ClosureExprs are common enough that we should give
diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp
index c2c6664..08b73ed 100644
--- a/lib/Sema/CSDiagnostics.cpp
+++ b/lib/Sema/CSDiagnostics.cpp
@@ -271,12 +271,12 @@
return false;
auto &last = path.back();
- if (last.getKind() != ConstraintLocator::Archetype)
+ if (last.getKind() != ConstraintLocator::GenericParameter)
return false;
- auto *archetype = last.getArchetype();
+ auto *paramTy = last.getGenericParameter();
emitDiagnostic(anchor->getLoc(), diag::converting_noescape_to_type,
- archetype);
+ paramTy);
return true;
}
diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp
index d75bb0a..2cfdb67 100644
--- a/lib/Sema/CSSimplify.cpp
+++ b/lib/Sema/CSSimplify.cpp
@@ -1532,7 +1532,7 @@
// represent an opened archetype. If we allowed this it would allow
// the noescape function to potentially escape.
if (auto *fnTy = type->getAs<FunctionType>()) {
- if (fnTy->isNoEscape() && typeVar->getImpl().getArchetype()) {
+ if (fnTy->isNoEscape() && typeVar->getImpl().getGenericParameter()) {
if (shouldAttemptFixes()) {
auto *fix = MarkExplicitlyEscaping::create(
*this, getConstraintLocator(locator));
diff --git a/lib/Sema/ConstraintLocator.cpp b/lib/Sema/ConstraintLocator.cpp
index c107aec..6b84550 100644
--- a/lib/Sema/ConstraintLocator.cpp
+++ b/lib/Sema/ConstraintLocator.cpp
@@ -33,8 +33,8 @@
for (auto elt : path) {
id.AddInteger(elt.getKind());
switch (elt.getKind()) {
- case Archetype:
- id.AddPointer(elt.getArchetype()->getCanonicalType().getPointer());
+ case GenericParameter:
+ id.AddPointer(elt.getGenericParameter());
break;
case Requirement:
@@ -109,8 +109,8 @@
for (auto elt : getPath()) {
out << " -> ";
switch (elt.getKind()) {
- case Archetype:
- out << "archetype '" << elt.getArchetype()->getString() << "'";
+ case GenericParameter:
+ out << "generic parameter '" << elt.getGenericParameter()->getString() << "'";
break;
case ApplyArgument:
diff --git a/lib/Sema/ConstraintLocator.h b/lib/Sema/ConstraintLocator.h
index 0cb7d41..83e5de5 100644
--- a/lib/Sema/ConstraintLocator.h
+++ b/lib/Sema/ConstraintLocator.h
@@ -59,10 +59,10 @@
ApplyFunction,
/// Matching an argument to a parameter.
ApplyArgToParam,
- /// \brief An archetype being opened.
+ /// \brief A generic parameter being opened.
///
- /// Also contains the archetype itself.
- Archetype,
+ /// Also contains the generic parameter type itself.
+ GenericParameter,
/// \brief The argument type of a function.
FunctionArgument,
/// \brief The result type of a function.
@@ -133,7 +133,7 @@
switch (kind) {
case ApplyArgument:
case ApplyFunction:
- case Archetype:
+ case GenericParameter:
case FunctionArgument:
case FunctionResult:
case OptionalPayload:
@@ -205,7 +205,7 @@
case RValueAdjustment:
case SubscriptMember:
case OpenedGeneric:
- case Archetype:
+ case GenericParameter:
case GenericArgument:
case NamedTupleElement:
case TupleElement:
@@ -233,7 +233,7 @@
class PathElement {
/// \brief Describes the kind of data stored here.
enum StoredKind : unsigned char {
- StoredArchetype,
+ StoredGenericParameter,
StoredRequirement,
StoredWitness,
StoredKindAndValue
@@ -291,13 +291,13 @@
"Path element requires value");
}
- PathElement(ArchetypeType *archetype)
- : storage((reinterpret_cast<uintptr_t>(archetype) >> 2)),
- storedKind(StoredArchetype)
+ PathElement(GenericTypeParamType *type)
+ : storage((reinterpret_cast<uintptr_t>(type) >> 2)),
+ storedKind(StoredGenericParameter)
{
- static_assert(alignof(ArchetypeType) >= 4,
+ static_assert(alignof(GenericTypeParamType) >= 4,
"archetypes insufficiently aligned");
- assert(getArchetype() == archetype);
+ assert(getGenericParameter() == type);
}
PathElement(PathElementKind kind, ValueDecl *decl)
@@ -353,8 +353,8 @@
/// \brief Retrieve the kind of path element.
PathElementKind getKind() const {
switch (static_cast<StoredKind>(storedKind)) {
- case StoredArchetype:
- return Archetype;
+ case StoredGenericParameter:
+ return GenericParameter;
case StoredRequirement:
return Requirement;
@@ -400,10 +400,12 @@
return reinterpret_cast<ValueDecl *>(storage << 2);
}
- /// \brief Retrieve the actual archetype for an archetype path element.
- ArchetypeType *getArchetype() const {
- assert(getKind() == Archetype && "Not an archetype path element");
- return reinterpret_cast<ArchetypeType *>(storage << 2);
+ /// \brief Retrieve the actual archetype for a generic parameter path
+ /// element.
+ GenericTypeParamType *getGenericParameter() const {
+ assert(getKind() == GenericParameter &&
+ "Not a generic parameter path element");
+ return reinterpret_cast<GenericTypeParamType *>(storage << 2);
}
/// Retrieve the declaration for a requirement path element.
diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp
index 3d457a7..926227f 100644
--- a/lib/Sema/ConstraintSystem.cpp
+++ b/lib/Sema/ConstraintSystem.cpp
@@ -801,7 +801,7 @@
SmallVector<LocatorPathElt, 2> pathElts;
Expr *anchor = locator.getLocatorParts(pathElts);
if (!pathElts.empty() &&
- pathElts.back().getKind() == ConstraintLocator::Archetype)
+ pathElts.back().getKind() == ConstraintLocator::GenericParameter)
return;
// If the locator is empty, ignore it.
@@ -1070,14 +1070,11 @@
return;
auto locatorPtr = getConstraintLocator(locator);
- auto *genericEnv = innerDC->getGenericEnvironmentOfContext();
// Create the type variables for the generic parameters.
for (auto gp : sig->getGenericParams()) {
- auto contextTy = GenericEnvironment::mapTypeIntoContext(genericEnv, gp);
- if (auto *archetype = contextTy->getAs<ArchetypeType>())
- locatorPtr = getConstraintLocator(
- locator.withPathElement(LocatorPathElt(archetype)));
+ locatorPtr = getConstraintLocator(
+ locator.withPathElement(LocatorPathElt(gp)));
auto typeVar = createTypeVariable(locatorPtr,
TVO_PrefersSubtypeBinding);
diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h
index 0bbd0d5..48ba066 100644
--- a/lib/Sema/ConstraintSystem.h
+++ b/lib/Sema/ConstraintSystem.h
@@ -279,8 +279,8 @@
return locator;
}
- /// \brief Retrieve the archetype opened by this type variable.
- ArchetypeType *getArchetype() const;
+ /// \brief Retrieve the generic parameter opened by this type variable.
+ GenericTypeParamType *getGenericParameter() const;
/// \brief Retrieve the representative of the equivalence class to which this
/// type variable belongs.
diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp
index ab3273c..eec2c2b 100644
--- a/lib/Sema/TypeCheckConstraints.cpp
+++ b/lib/Sema/TypeCheckConstraints.cpp
@@ -73,14 +73,16 @@
typeVar->getImpl().ParentOrFixed = ParentOrFixed;
}
-ArchetypeType *TypeVariableType::Implementation::getArchetype() const {
- // Check whether we have a path that terminates at an archetype locator.
+GenericTypeParamType *
+TypeVariableType::Implementation::getGenericParameter() const {
+ // Check whether we have a path that terminates at a generic parameter
+ // locator.
if (!locator || locator->getPath().empty() ||
- locator->getPath().back().getKind() != ConstraintLocator::Archetype)
+ locator->getPath().back().getKind() != ConstraintLocator::GenericParameter)
return nullptr;
// Retrieve the archetype.
- return locator->getPath().back().getArchetype();
+ return locator->getPath().back().getGenericParameter();
}
// Only allow allocation of resolved overload set list items using the
diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp
index f9b0e10..31686eb 100644
--- a/lib/Serialization/Deserialization.cpp
+++ b/lib/Serialization/Deserialization.cpp
@@ -5305,15 +5305,6 @@
conformance->setWitness(req, Witness::forOpaque(req));
};
- // Requirement -> synthetic map.
- if (auto syntheticSig = getGenericSignature(*rawIDIter++)) {
- // Create the synthetic environment.
- syntheticEnv = syntheticSig->createGenericEnvironment();
- }
-
- // Requirement -> synthetic substitutions.
- SubstitutionMap reqToSyntheticSubs = getSubstitutionMap(*rawIDIter++);
-
// Witness substitutions.
SubstitutionMap witnessSubstitutions = getSubstitutionMap(*rawIDIter++);
@@ -5324,8 +5315,7 @@
}
// Set the witness.
- trySetWitness(Witness(witness, witnessSubstitutions,
- syntheticEnv, reqToSyntheticSubs));
+ trySetWitness(Witness::forDeserialized(witness, witnessSubstitutions));
}
assert(rawIDIter <= rawIDs.end() && "read too much");
diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp
index 66013ce..905619e 100644
--- a/lib/Serialization/Serialization.cpp
+++ b/lib/Serialization/Serialization.cpp
@@ -1595,18 +1595,21 @@
// If there is no witness, we're done.
if (!witness.getDecl()) return;
- if (auto *genericEnv = witness.getSyntheticEnvironment()) {
- // Generic signature.
- auto *genericSig = genericEnv->getGenericSignature();
- data.push_back(addGenericSignatureRef(genericSig));
- } else {
- data.push_back(/*null generic signature*/0);
- }
+ auto subs = witness.getSubstitutions();
- data.push_back(
- addSubstitutionMapRef(witness.getRequirementToSyntheticSubs()));
- data.push_back(
- addSubstitutionMapRef(witness.getSubstitutions()));
+ // Canonicalize away typealiases, since these substitutions aren't used
+ // for diagnostics and we reference fewer declarations that way.
+ subs = subs.getCanonical();
+
+ // Map archetypes to type parameters, since we always substitute them
+ // away. Note that in a merge-modules pass, we're serializing conformances
+ // that we deserialized, so they will already have their replacement types
+ // in terms of interface types; hence the hasArchetypes() check is
+ // necessary for correctness, not just as a fast path.
+ if (subs.hasArchetypes())
+ subs = subs.mapReplacementTypesOutOfContext();
+
+ data.push_back(addSubstitutionMapRef(subs));
});
unsigned numSignatureConformances =
diff --git a/test/Frontend/debug-generic-signatures.swift b/test/Frontend/debug-generic-signatures.swift
index cff7ce0..3ec6d50 100644
--- a/test/Frontend/debug-generic-signatures.swift
+++ b/test/Frontend/debug-generic-signatures.swift
@@ -118,8 +118,7 @@
// CHECK-NEXT: (normal_conformance type=Recur protocol=P2 (details printed above))))
// CHECK-NEXT: (conformance type=U
// CHECK-NEXT: (normal_conformance type=Recur protocol=P2 (details printed above))))
-// CHECK-NEXT: conforms_to: NonRecur P2
-// CHECK-NEXT: conforms_to: Recur P2
+// CHECK-NEXT: (conditional requirements unable to be computed)
// CHECK-NEXT: (normal_conformance type=Super<T, U> protocol=P2
// CHECK-NEXT: (assoc_type req=A type=T)
// CHECK-NEXT: (assoc_type req=B type=T)
diff --git a/test/Serialization/Inputs/conformance-multi-file-other.swift b/test/Serialization/Inputs/conformance-multi-file-other.swift
index 73b1aa2..bac7587 100644
--- a/test/Serialization/Inputs/conformance-multi-file-other.swift
+++ b/test/Serialization/Inputs/conformance-multi-file-other.swift
@@ -9,3 +9,9 @@
extension Base : BaseProto {
public func method() {}
}
+
+// Make sure we can serialize witness substitutions where replacement types
+// involve generic parameters.
+public class GenericWitness<T> : BaseProto {
+ public func method() {}
+}
diff --git a/test/decl/protocol/req/recursion.swift b/test/decl/protocol/req/recursion.swift
index 59c1217..9fb66a3 100644
--- a/test/decl/protocol/req/recursion.swift
+++ b/test/decl/protocol/req/recursion.swift
@@ -48,7 +48,7 @@
// expected-error@-2 {{generic struct 'S' references itself}}
func f(a: A.T) {
g(a: id(t: a))
- // expected-error@-1 {{generic parameter 'T' could not be inferred}}
+ // expected-error@-1 {{cannot convert value of type 'A.T' to expected argument type 'S<_>'}}
_ = A.T.self
}
diff --git a/validation-test/compiler_crashers_2_fixed/0158-rdar40165062.swift b/validation-test/compiler_crashers_2_fixed/0158-rdar40165062.swift
index 388f1b7..e5cf3b6 100644
--- a/validation-test/compiler_crashers_2_fixed/0158-rdar40165062.swift
+++ b/validation-test/compiler_crashers_2_fixed/0158-rdar40165062.swift
@@ -1,9 +1,11 @@
// RUN: %target-typecheck-verify-swift
-struct Foo<T, U> {
+struct Foo<T, U> { // expected-note {{'U' declared as parameter to type 'Foo'}}
var value: U
func bar() -> Foo<T, U> {
- return Foo(value) // expected-error {{generic parameter 'T' could not be inferred}}
+ return Foo(value)
+ // expected-error@-1 {{generic parameter 'U' could not be inferred}}
+ // expected-note@-2 {{explicitly specify the generic arguments to fix this issue}}
}
}