Skip to content

Commit 7c16b27

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 9a02283 commit 7c16b27

File tree

9 files changed

+105
-175
lines changed

9 files changed

+105
-175
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 = true) 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
@@ -5532,12 +5532,7 @@ Expr *getArgumentLabelTargetExpr(Expr *fn);
55325532
/// variable and anything that depends on it to their non-dependent bounds.
55335533
Type typeEraseOpenedExistentialReference(Type type, Type existentialBaseType,
55345534
TypeVariableType *openedTypeVar,
5535-
TypePosition outermostPosition,
5536-
bool wantNonDependentBound = true);
5537-
5538-
Type transformFn(Type type, Type existentialBaseType,
5539-
TypePosition initialPos);
5540-
5535+
TypePosition outermostPosition);
55415536

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

lib/AST/GenericSignature.cpp

Lines changed: 22 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -626,149 +626,41 @@ 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, /*wantNonDependentBound=*/false);
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
636644
// If the class contains a type parameter that cannot be reduced,
637645
// try looking for a non-dependent superclass.
638646
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;
647+
while (superclass->hasTypeParameter()) {
648+
superclass = getReducedType(superclass);
649+
if (wantDependentBound && !superclass->hasTypeParameter()) {
655650
break;
656651
}
657652
superclass = superclass->getSuperclass();
658653
}
654+
659655
if (superclass) {
660656
types.push_back(superclass);
661657
hasExplicitAnyObject = false;
662658
}
663659
}
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-
}
739-
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-
}
770660

771-
for (auto proto : getRequiredProtocols(type)) {
661+
// If the protocol contains reduced type, erase to it.
662+
// Keep going until we hit a type that has no unresolved components.
663+
for (auto *proto : getRequiredProtocols(type)) {
772664
if (proto->requiresClass())
773665
hasExplicitAnyObject = false;
774666

@@ -813,7 +705,6 @@ Type GenericSignatureImpl::getDependentUpperBounds(Type type) const {
813705
if (!hasInnerGenericParam)
814706
argTypes.push_back(reducedType);
815707
}
816-
817708
// We should have either constrained all primary associated types,
818709
// or none of them.
819710
if (!argTypes.empty()) {
@@ -824,16 +715,17 @@ Type GenericSignatureImpl::getDependentUpperBounds(Type type) const {
824715
abort();
825716
}
826717

827-
types.push_back(ParameterizedProtocolType::get(ctx, baseType, argTypes));
718+
types.push_back(ParameterizedProtocolType::get(getASTContext(),
719+
baseType, argTypes));
828720
continue;
829721
}
830722
}
831-
832-
types.push_back(baseType);
723+
wantDependentBound ? types.push_back(proto->getDeclaredInterfaceType())
724+
: types.push_back(baseType);
833725
}
834726

835-
auto constraint = ProtocolCompositionType::get(
836-
ctx, types, hasExplicitAnyObject);
727+
auto constraint = ProtocolCompositionType::get(getASTContext(), types,
728+
hasExplicitAnyObject);
837729

838730
if (!constraint->isConstraintType()) {
839731
assert(constraint->getClassOrBoundGenericClass());

lib/Sema/CSDiagnostics.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8761,7 +8761,7 @@ bool MissingExplicitExistentialCoercion::fixItRequiresParens() const {
87618761
void MissingExplicitExistentialCoercion::fixIt(
87628762
InFlightDiagnostic &diagnostic) const {
87638763

8764-
if (ErasedResultType->hasDependentMember())
8764+
if (ErasedResultType->hasTypeParameter())
87658765
return;
87668766

87678767
bool requiresParens = fixItRequiresParens();

lib/Sema/CSFix.cpp

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2496,10 +2496,8 @@ bool AddExplicitExistentialCoercion::isRequired(
24962496
if (!existentialType)
24972497
return Action::SkipChildren;
24982498

2499-
// let's grab the dependent upper bound here instead of nondependent
25002499
auto erasedMemberTy = typeEraseOpenedExistentialReference(
2501-
Type(member), *existentialType, typeVar, TypePosition::Covariant,
2502-
false);
2500+
Type(member), *existentialType, typeVar, TypePosition::Covariant);
25032501

25042502
// If result is an existential type and the base has `where` clauses
25052503
// associated with its associated types, the call needs a coercion.
@@ -2510,13 +2508,7 @@ bool AddExplicitExistentialCoercion::isRequired(
25102508
}
25112509

25122510
if (erasedMemberTy->isExistentialType() &&
2513-
(erasedMemberTy->hasDependentMember() ||
2514-
erasedMemberTy->hasTypeParameter())) {
2515-
RequiresCoercion = true;
2516-
return Action::Stop;
2517-
}
2518-
2519-
if (erasedMemberTy->hasTypeVariable()) {
2511+
erasedMemberTy->hasTypeParameter()) {
25202512
RequiresCoercion = true;
25212513
return Action::Stop;
25222514
}
@@ -2568,7 +2560,6 @@ bool AddExplicitExistentialCoercion::isRequired(
25682560
case RequirementKind::Layout: {
25692561
if (isAnchoredOn(req.getFirstType(), member->getAssocType()))
25702562
return true;
2571-
25722563
break;
25732564
}
25742565

lib/Sema/ConstraintSystem.cpp

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1997,10 +1997,8 @@ static bool isMainDispatchQueueMember(ConstraintLocator *locator) {
19971997
///
19981998
/// \note If a 'Self'-rooted type parameter is bound to a concrete type, this
19991999
/// routine will recurse into the concrete type.
2000-
static Type
2001-
typeEraseExistentialSelfReferences(Type refTy, Type baseTy,
2002-
TypePosition outermostPosition,
2003-
bool wantNonDependentBound = true) {
2000+
static Type typeEraseExistentialSelfReferences(Type refTy, Type baseTy,
2001+
TypePosition outermostPosition) {
20042002
assert(baseTy->isExistentialType());
20052003
if (!refTy->hasTypeParameter()) {
20062004
return refTy;
@@ -2103,9 +2101,7 @@ typeEraseExistentialSelfReferences(Type refTy, Type baseTy,
21032101
if (t->is<GenericTypeParamType>()) {
21042102
erasedTy = baseTy;
21052103
} else {
2106-
erasedTy = wantNonDependentBound
2107-
? existentialSig->getNonDependentUpperBounds(t)
2108-
: existentialSig->getDependentUpperBounds(t);
2104+
erasedTy = existentialSig->getNonDependentUpperBounds(t);
21092105
}
21102106

21112107
if (metatypeDepth) {
@@ -2121,7 +2117,7 @@ typeEraseExistentialSelfReferences(Type refTy, Type baseTy,
21212117

21222118
Type constraints::typeEraseOpenedExistentialReference(
21232119
Type type, Type existentialBaseType, TypeVariableType *openedTypeVar,
2124-
TypePosition outermostPosition, bool wantNonDependentBound) {
2120+
TypePosition outermostPosition) {
21252121
Type selfGP = GenericTypeParamType::get(false, 0, 0, type->getASTContext());
21262122

21272123
// First, temporarily reconstitute the 'Self' generic parameter.
@@ -2138,8 +2134,8 @@ Type constraints::typeEraseOpenedExistentialReference(
21382134
});
21392135

21402136
// Then, type-erase occurrences of covariant 'Self'-rooted type parameters.
2141-
type = typeEraseExistentialSelfReferences(
2142-
type, existentialBaseType, outermostPosition, wantNonDependentBound);
2137+
type = typeEraseExistentialSelfReferences(type, existentialBaseType,
2138+
outermostPosition);
21432139

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

0 commit comments

Comments
 (0)