Skip to content

Commit 7ffbf58

Browse files
committed
AST: Add GenericSignatureImpl::getDependentUpperBounds()
1 parent 7c34c3b commit 7ffbf58

File tree

2 files changed

+98
-0
lines changed

2 files changed

+98
-0
lines changed

include/swift/AST/GenericSignature.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,13 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final
457457
/// will return an instance of \c ExistentialType.
458458
Type getNonDependentUpperBounds(Type type) const;
459459

460+
/// Given a type parameter, compute the most specific supertype (upper bound)
461+
/// that is possibly dependent on other type parameters.
462+
///
463+
/// \note If the upper bound is a protocol or protocol composition,
464+
/// will return an instance of \c ExistentialType.
465+
Type getDependentUpperBounds(Type type) const;
466+
460467
static void Profile(llvm::FoldingSetNodeID &ID,
461468
TypeArrayView<GenericTypeParamType> genericParams,
462469
ArrayRef<Requirement> requirements);

lib/AST/GenericSignature.cpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,97 @@ Type GenericSignatureImpl::getNonDependentUpperBounds(Type type) const {
626626
return boundsTy;
627627
}
628628

629+
Type GenericSignatureImpl::getDependentUpperBounds(Type type) const {
630+
assert(type->isTypeParameter());
631+
632+
llvm::SmallVector<Type, 2> types;
633+
634+
auto &ctx = type->getASTContext();
635+
636+
bool hasExplicitAnyObject = requiresClass(type);
637+
638+
// FIXME: If the superclass bound is implied by one of our protocols, we
639+
// shouldn't add it to the constraint type.
640+
if (Type superclass = getSuperclassBound(type)) {
641+
types.push_back(superclass);
642+
hasExplicitAnyObject = false;
643+
}
644+
645+
for (auto proto : getRequiredProtocols(type)) {
646+
if (proto->requiresClass())
647+
hasExplicitAnyObject = false;
648+
649+
auto *baseType = proto->getDeclaredInterfaceType()->castTo<ProtocolType>();
650+
651+
auto primaryAssocTypes = proto->getPrimaryAssociatedTypes();
652+
if (!primaryAssocTypes.empty()) {
653+
SmallVector<Type, 2> argTypes;
654+
655+
// Attempt to recover same-type requirements on primary associated types.
656+
for (auto *assocType : primaryAssocTypes) {
657+
// For each primary associated type A of P, compute the reduced type
658+
// of T.[P]A.
659+
auto *memberType = DependentMemberType::get(type, assocType);
660+
auto reducedType = getReducedType(memberType);
661+
662+
// If the reduced type is at a lower depth than the root generic
663+
// parameter of T, then it's constrained.
664+
bool hasOuterGenericParam = false;
665+
bool hasInnerGenericParam = false;
666+
reducedType.visit([&](Type t) {
667+
if (auto *paramTy = t->getAs<GenericTypeParamType>()) {
668+
unsigned rootDepth = type->getRootGenericParam()->getDepth();
669+
if (paramTy->getDepth() == rootDepth)
670+
hasInnerGenericParam = true;
671+
else {
672+
assert(paramTy->getDepth() < rootDepth);
673+
hasOuterGenericParam = true;
674+
}
675+
}
676+
});
677+
678+
if (hasInnerGenericParam && hasOuterGenericParam) {
679+
llvm::errs() << "Weird same-type requirements?\n";
680+
llvm::errs() << "Interface type: " << type << "\n";
681+
llvm::errs() << "Member type: " << memberType << "\n";
682+
llvm::errs() << "Reduced member type: " << reducedType << "\n";
683+
llvm::errs() << GenericSignature(this) << "\n";
684+
abort();
685+
}
686+
687+
if (!hasInnerGenericParam)
688+
argTypes.push_back(reducedType);
689+
}
690+
691+
// We should have either constrained all primary associated types,
692+
// or none of them.
693+
if (!argTypes.empty()) {
694+
if (argTypes.size() != primaryAssocTypes.size()) {
695+
llvm::errs() << "Not all primary associated types constrained?\n";
696+
llvm::errs() << "Interface type: " << type << "\n";
697+
llvm::errs() << GenericSignature(this) << "\n";
698+
abort();
699+
}
700+
701+
types.push_back(ParameterizedProtocolType::get(ctx, baseType, argTypes));
702+
continue;
703+
}
704+
}
705+
706+
types.push_back(baseType);
707+
}
708+
709+
auto constraint = ProtocolCompositionType::get(
710+
ctx, types, hasExplicitAnyObject);
711+
712+
if (!constraint->isConstraintType()) {
713+
assert(constraint->getClassOrBoundGenericClass());
714+
return constraint;
715+
}
716+
717+
return ExistentialType::get(constraint);
718+
}
719+
629720
void GenericSignature::Profile(llvm::FoldingSetNodeID &id) const {
630721
return GenericSignature::Profile(id, getPointer()->getGenericParams(),
631722
getPointer()->getRequirements());

0 commit comments

Comments
 (0)