Skip to content

Commit a9f1096

Browse files
committed
[Generic Signature] Unify generic upper bound functions
Opened existentials should be erased to the dependent upper bound if the dependent member can be reduced to a concrete type. This allows the generic signature to support parameterized protocol types and bound generic class types by producing a more specific constraint instead of just a plain protocol or class.
1 parent 5c818b3 commit a9f1096

File tree

9 files changed

+106
-183
lines changed

9 files changed

+106
-183
lines changed

include/swift/AST/GenericSignature.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,8 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final
360360
/// Determine whether the given dependent type is required to be a class.
361361
bool requiresClass(Type type) const;
362362

363+
Type getUpperBound(Type type, bool wantDependentUpperBound = false) const;
364+
363365
/// Determine the superclass bound on the given dependent type.
364366
Type getSuperclassBound(Type type) const;
365367

include/swift/Sema/ConstraintSystem.h

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5579,12 +5579,7 @@ Expr *getArgumentLabelTargetExpr(Expr *fn);
55795579
/// variable and anything that depends on it to their non-dependent bounds.
55805580
Type typeEraseOpenedExistentialReference(Type type, Type existentialBaseType,
55815581
TypeVariableType *openedTypeVar,
5582-
TypePosition outermostPosition,
5583-
bool wantNonDependentBound = true);
5584-
5585-
Type transformFn(Type type, Type existentialBaseType,
5586-
TypePosition initialPos);
5587-
5582+
TypePosition outermostPosition);
55885583

55895584
/// Returns true if a reference to a member on a given base type will apply
55905585
/// its curried self parameter, assuming it has one.

lib/AST/GenericSignature.cpp

Lines changed: 18 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -626,149 +626,36 @@ unsigned GenericSignatureImpl::getGenericParamOrdinal(
626626
}
627627

628628
Type GenericSignatureImpl::getNonDependentUpperBounds(Type type) const {
629+
return getUpperBound(type);
630+
}
631+
632+
Type GenericSignatureImpl::getDependentUpperBounds(Type type) const {
633+
return getUpperBound(type, /*wantDependentBound=*/true);
634+
}
635+
636+
Type GenericSignatureImpl::getUpperBound(Type type,
637+
bool wantDependentBound) const {
629638
assert(type->isTypeParameter());
630639

631640
bool hasExplicitAnyObject = requiresClass(type);
632641

633642
llvm::SmallVector<Type, 2> types;
634643

635-
// Class Inheritence
636-
// If the class contains a type parameter that cannot be reduced,
637-
// try looking for a non-dependent superclass.
638644
if (Type superclass = getSuperclassBound(type)) {
639-
while (superclass &&
640-
superclass->hasTypeParameter()) { // check if the current protocol
641-
// has an associated type]
642-
auto *boundgeneric = superclass->castTo<BoundGenericClassType>();
643-
644-
SmallVector<Type, 2> argTypes;
645-
646-
for (Type argTy : boundgeneric->getGenericArgs()) {
647-
argTypes.push_back(getReducedType(argTy));
648-
}
649-
650-
boundgeneric = BoundGenericClassType::get(
651-
boundgeneric->getDecl(), boundgeneric->getParent(), argTypes);
652-
if (!boundgeneric->hasDependentMember() &&
653-
!boundgeneric->hasTypeParameter()) {
654-
superclass = boundgeneric;
645+
do {
646+
superclass = getReducedType(superclass);
647+
if (wantDependentBound || !superclass->hasTypeParameter()) {
655648
break;
656649
}
657-
superclass = superclass->getSuperclass();
658-
}
650+
} while ((superclass = superclass->getSuperclass()));
651+
659652
if (superclass) {
660653
types.push_back(superclass);
661654
hasExplicitAnyObject = false;
662655
}
663656
}
664-
665-
// Protocol Inheritence
666-
// If there is a reduced type, erase to it.
667-
// Otherwise keep going until we hit a type that has unresolved components.
668-
for (auto *proto : getRequiredProtocols(type)) {
669-
if (proto->requiresClass())
670-
hasExplicitAnyObject = false;
671-
672-
auto *baseType = proto->getDeclaredInterfaceType()->castTo<ProtocolType>();
673-
674-
auto primaryAssocTypes = proto->getPrimaryAssociatedTypes();
675-
if (!primaryAssocTypes.empty()) {
676-
SmallVector<Type, 2> argTypes;
677-
678-
// Attempt to recover same-type requirements on primary associated types.
679-
for (auto *assocType : primaryAssocTypes) {
680-
// For each primary associated type A of P, compute the reduced type
681-
// of T.[P]A.
682-
auto *memberType = DependentMemberType::get(type, assocType);
683-
auto reducedType = getReducedType(memberType);
684-
685-
// If the reduced type is at a lower depth than the root generic
686-
// parameter of T, then it's constrained.
687-
bool hasOuterGenericParam = false;
688-
bool hasInnerGenericParam = false;
689-
reducedType.visit([&](Type t) {
690-
if (auto *paramTy = t->getAs<GenericTypeParamType>()) {
691-
unsigned rootDepth = type->getRootGenericParam()->getDepth();
692-
if (paramTy->getDepth() == rootDepth)
693-
hasInnerGenericParam = true;
694-
else {
695-
assert(paramTy->getDepth() < rootDepth);
696-
hasOuterGenericParam = true;
697-
}
698-
}
699-
});
700-
701-
if (hasInnerGenericParam && hasOuterGenericParam) {
702-
llvm::errs() << "Weird same-type requirements?\n";
703-
llvm::errs() << "Interface type: " << type << "\n";
704-
llvm::errs() << "Member type: " << memberType << "\n";
705-
llvm::errs() << "Reduced member type: " << reducedType << "\n";
706-
llvm::errs() << GenericSignature(this) << "\n";
707-
abort();
708-
}
709-
710-
if (!hasInnerGenericParam)
711-
argTypes.push_back(reducedType);
712-
}
713-
// We should have either constrained all primary associated types,
714-
// or none of them.
715-
if (!argTypes.empty()) {
716-
if (argTypes.size() != primaryAssocTypes.size()) {
717-
llvm::errs() << "Not all primary associated types constrained?\n";
718-
llvm::errs() << "Interface type: " << type << "\n";
719-
llvm::errs() << GenericSignature(this) << "\n";
720-
abort();
721-
}
722-
723-
types.push_back(ParameterizedProtocolType::get(getASTContext(), baseType, argTypes));
724-
continue;
725-
}
726-
}
727-
728-
types.push_back(baseType);
729-
}
730-
731-
auto constraint = ProtocolCompositionType::get(
732-
getASTContext(), types,
733-
hasExplicitAnyObject);
734-
735-
if (!constraint->isConstraintType()) {
736-
assert(constraint->getClassOrBoundGenericClass());
737-
return constraint;
738-
}
739657

740-
return ExistentialType::get(constraint);
741-
}
742-
743-
Type GenericSignatureImpl::getDependentUpperBounds(Type type) const {
744-
assert(type->isTypeParameter());
745-
746-
llvm::SmallVector<Type, 2> types;
747-
748-
auto &ctx = type->getASTContext();
749-
750-
bool hasExplicitAnyObject = requiresClass(type);
751-
752-
// FIXME: If the superclass bound is implied by one of our protocols, we
753-
// shouldn't add it to the constraint type.
754-
if (Type superclass = getSuperclassBound(type)) {
755-
hasExplicitAnyObject = false;
756-
757-
if (auto *boundgeneric = superclass->getAs<BoundGenericClassType>()) {
758-
SmallVector<Type, 2> argTypes;
759-
760-
for (Type argTy : boundgeneric->getGenericArgs()) {
761-
argTypes.push_back(getReducedType(argTy));
762-
}
763-
boundgeneric = BoundGenericClassType::get(
764-
boundgeneric->getDecl(), boundgeneric->getParent(), argTypes);
765-
types.push_back(boundgeneric);
766-
} else {
767-
types.push_back(superclass);
768-
}
769-
}
770-
771-
for (auto proto : getRequiredProtocols(type)) {
658+
for (auto *proto : getRequiredProtocols(type)) {
772659
if (proto->requiresClass())
773660
hasExplicitAnyObject = false;
774661

@@ -824,16 +711,15 @@ Type GenericSignatureImpl::getDependentUpperBounds(Type type) const {
824711
//
825712
// In that case just add the base type in the default branch below.
826713
if (argTypes.size() == primaryAssocTypes.size()) {
827-
types.push_back(ParameterizedProtocolType::get(ctx, baseType, argTypes));
714+
types.push_back(ParameterizedProtocolType::get(getASTContext(), baseType, argTypes));
828715
continue;
829716
}
830717
}
831-
832718
types.push_back(baseType);
833719
}
834720

835-
auto constraint = ProtocolCompositionType::get(
836-
ctx, types, hasExplicitAnyObject);
721+
auto constraint = ProtocolCompositionType::get(getASTContext(), types,
722+
hasExplicitAnyObject);
837723

838724
if (!constraint->isConstraintType()) {
839725
assert(constraint->getClassOrBoundGenericClass());

lib/Sema/CSDiagnostics.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8820,7 +8820,7 @@ bool MissingExplicitExistentialCoercion::fixItRequiresParens() const {
88208820
void MissingExplicitExistentialCoercion::fixIt(
88218821
InFlightDiagnostic &diagnostic) const {
88228822

8823-
if (ErasedResultType->hasDependentMember())
8823+
if (ErasedResultType->hasTypeParameter())
88248824
return;
88258825

88268826
bool requiresParens = fixItRequiresParens();

lib/Sema/CSFix.cpp

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2503,10 +2503,8 @@ bool AddExplicitExistentialCoercion::isRequired(
25032503
if (!existentialType)
25042504
return Action::SkipChildren;
25052505

2506-
// let's grab the dependent upper bound here instead of nondependent
25072506
auto erasedMemberTy = typeEraseOpenedExistentialReference(
2508-
Type(member), *existentialType, typeVar, TypePosition::Covariant,
2509-
false);
2507+
Type(member), *existentialType, typeVar, TypePosition::Covariant);
25102508

25112509
// If result is an existential type and the base has `where` clauses
25122510
// associated with its associated types, the call needs a coercion.
@@ -2517,13 +2515,7 @@ bool AddExplicitExistentialCoercion::isRequired(
25172515
}
25182516

25192517
if (erasedMemberTy->isExistentialType() &&
2520-
(erasedMemberTy->hasDependentMember() ||
2521-
erasedMemberTy->hasTypeParameter())) {
2522-
RequiresCoercion = true;
2523-
return Action::Stop;
2524-
}
2525-
2526-
if (erasedMemberTy->hasTypeVariable()) {
2518+
erasedMemberTy->hasTypeParameter()) {
25272519
RequiresCoercion = true;
25282520
return Action::Stop;
25292521
}
@@ -2575,7 +2567,6 @@ bool AddExplicitExistentialCoercion::isRequired(
25752567
case RequirementKind::Layout: {
25762568
if (isAnchoredOn(req.getFirstType(), member->getAssocType()))
25772569
return true;
2578-
25792570
break;
25802571
}
25812572

lib/Sema/ConstraintSystem.cpp

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2053,10 +2053,8 @@ static bool isMainDispatchQueueMember(ConstraintLocator *locator) {
20532053
///
20542054
/// \note If a 'Self'-rooted type parameter is bound to a concrete type, this
20552055
/// routine will recurse into the concrete type.
2056-
static Type
2057-
typeEraseExistentialSelfReferences(Type refTy, Type baseTy,
2058-
TypePosition outermostPosition,
2059-
bool wantNonDependentBound = true) {
2056+
static Type typeEraseExistentialSelfReferences(Type refTy, Type baseTy,
2057+
TypePosition outermostPosition) {
20602058
assert(baseTy->isExistentialType());
20612059
if (!refTy->hasTypeParameter()) {
20622060
return refTy;
@@ -2159,9 +2157,7 @@ typeEraseExistentialSelfReferences(Type refTy, Type baseTy,
21592157
if (t->is<GenericTypeParamType>()) {
21602158
erasedTy = baseTy;
21612159
} else {
2162-
erasedTy = wantNonDependentBound
2163-
? existentialSig->getNonDependentUpperBounds(t)
2164-
: existentialSig->getDependentUpperBounds(t);
2160+
erasedTy = existentialSig->getNonDependentUpperBounds(t);
21652161
}
21662162

21672163
if (metatypeDepth) {
@@ -2177,7 +2173,7 @@ typeEraseExistentialSelfReferences(Type refTy, Type baseTy,
21772173

21782174
Type constraints::typeEraseOpenedExistentialReference(
21792175
Type type, Type existentialBaseType, TypeVariableType *openedTypeVar,
2180-
TypePosition outermostPosition, bool wantNonDependentBound) {
2176+
TypePosition outermostPosition) {
21812177
Type selfGP = GenericTypeParamType::get(false, 0, 0, type->getASTContext());
21822178

21832179
// First, temporarily reconstitute the 'Self' generic parameter.
@@ -2194,8 +2190,8 @@ Type constraints::typeEraseOpenedExistentialReference(
21942190
});
21952191

21962192
// Then, type-erase occurrences of covariant 'Self'-rooted type parameters.
2197-
type = typeEraseExistentialSelfReferences(
2198-
type, existentialBaseType, outermostPosition, wantNonDependentBound);
2193+
type = typeEraseExistentialSelfReferences(type, existentialBaseType,
2194+
outermostPosition);
21992195

22002196
// Finally, swap the 'Self'-corresponding type variable back in.
22012197
return type.transformRec([&](TypeBase *t) -> Optional<Type> {

0 commit comments

Comments
 (0)