Skip to content

Commit 4338a55

Browse files
committed
ASTDemangler: Add support for constrained existential compositions
1 parent ca0e984 commit 4338a55

File tree

2 files changed

+100
-41
lines changed

2 files changed

+100
-41
lines changed

lib/AST/ASTDemangler.cpp

Lines changed: 64 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -767,65 +767,88 @@ Type ASTBuilder::createExistentialMetatypeType(
767767
Type ASTBuilder::createConstrainedExistentialType(
768768
Type base, ArrayRef<BuiltRequirement> constraints,
769769
ArrayRef<BuiltInverseRequirement> inverseRequirements) {
770-
Type constrainedBase;
771-
772-
if (auto baseTy = base->getAs<ProtocolType>()) {
773-
auto baseDecl = baseTy->getDecl();
774-
llvm::SmallDenseMap<Identifier, Type> cmap;
775-
for (const auto &req : constraints) {
776-
switch (req.getKind()) {
777-
case RequirementKind::SameShape:
778-
llvm_unreachable("Same-shape requirement not supported here");
779-
case RequirementKind::Conformance:
780-
case RequirementKind::Superclass:
781-
case RequirementKind::Layout:
782-
continue;
770+
llvm::SmallDenseMap<Identifier, Type> primaryAssociatedTypes;
771+
llvm::SmallDenseSet<Identifier> claimed;
772+
773+
for (const auto &req : constraints) {
774+
switch (req.getKind()) {
775+
case RequirementKind::SameShape:
776+
case RequirementKind::Conformance:
777+
case RequirementKind::Superclass:
778+
case RequirementKind::Layout:
779+
break;
783780

784-
case RequirementKind::SameType:
785-
if (auto *DMT = req.getFirstType()->getAs<DependentMemberType>())
786-
cmap[DMT->getName()] = req.getSecondType();
781+
case RequirementKind::SameType: {
782+
if (auto *memberTy = req.getFirstType()->getAs<DependentMemberType>()) {
783+
if (memberTy->getBase()->is<GenericTypeParamType>()) {
784+
// This is the only case we understand so far.
785+
primaryAssociatedTypes[memberTy->getName()] = req.getSecondType();
786+
continue;
787+
}
787788
}
789+
break;
790+
}
788791
}
792+
793+
// If we end here, we didn't recognize this requirement.
794+
return Type();
795+
}
796+
797+
auto maybeFormParameterizedProtocolType = [&](ProtocolType *protoTy) -> Type {
798+
auto *proto = protoTy->getDecl();
799+
789800
llvm::SmallVector<Type, 4> args;
790-
for (auto *assocTy : baseDecl->getPrimaryAssociatedTypes()) {
791-
auto argTy = cmap.find(assocTy->getName());
792-
if (argTy == cmap.end()) {
793-
return Type();
794-
}
795-
args.push_back(argTy->getSecond());
801+
for (auto *assocTy : proto->getPrimaryAssociatedTypes()) {
802+
auto found = primaryAssociatedTypes.find(assocTy->getName());
803+
if (found == primaryAssociatedTypes.end())
804+
return protoTy;
805+
args.push_back(found->second);
806+
claimed.insert(found->first);
796807
}
797808

798809
// We may not have any arguments because the constrained existential is a
799810
// plain protocol with an inverse requirement.
800-
if (args.empty()) {
801-
constrainedBase =
802-
ProtocolType::get(baseDecl, baseTy, base->getASTContext());
803-
} else {
804-
constrainedBase =
805-
ParameterizedProtocolType::get(base->getASTContext(), baseTy, args);
806-
}
807-
} else if (base->isAny()) {
808-
// The only other case should be that we got an empty PCT, which is equal to
809-
// the Any type. The other constraints should have been encoded in the
810-
// existential's generic signature (and arrive as BuiltInverseRequirement).
811-
constrainedBase = base;
811+
if (args.empty())
812+
return protoTy;
813+
814+
return ParameterizedProtocolType::get(Ctx, protoTy, args);
815+
};
816+
817+
SmallVector<Type, 2> members;
818+
bool hasExplicitAnyObject = false;
819+
InvertibleProtocolSet inverses;
820+
821+
// We're given either a single protocol type, or a composition of protocol
822+
// types. Transform each protocol type to add arguments, if necessary.
823+
if (auto protoTy = base->getAs<ProtocolType>()) {
824+
members.push_back(maybeFormParameterizedProtocolType(protoTy));
812825
} else {
813-
return Type();
826+
auto compositionTy = base->castTo<ProtocolCompositionType>();
827+
hasExplicitAnyObject = compositionTy->hasExplicitAnyObject();
828+
ASSERT(compositionTy->getInverses().empty());
829+
830+
for (auto member : compositionTy->getMembers()) {
831+
if (auto *protoTy = member->getAs<ProtocolType>()) {
832+
members.push_back(maybeFormParameterizedProtocolType(protoTy));
833+
continue;
834+
}
835+
ASSERT(member->getClassOrBoundGenericClass());
836+
members.push_back(member);
837+
}
814838
}
815839

816-
assert(constrainedBase);
840+
// Make sure that all arguments were actually used.
841+
ASSERT(claimed.size() == primaryAssociatedTypes.size());
817842

818843
// Handle inverse requirements.
819844
if (!inverseRequirements.empty()) {
820-
InvertibleProtocolSet inverseSet;
821845
for (const auto &inverseReq : inverseRequirements) {
822-
inverseSet.insert(inverseReq.getKind());
846+
inverses.insert(inverseReq.getKind());
823847
}
824-
constrainedBase = ProtocolCompositionType::get(
825-
Ctx, { constrainedBase }, inverseSet, /*hasExplicitAnyObject=*/false);
826848
}
827849

828-
return ExistentialType::get(constrainedBase);
850+
return ExistentialType::get(ProtocolCompositionType::get(
851+
Ctx, members, inverses, hasExplicitAnyObject));
829852
}
830853

831854
Type ASTBuilder::createSymbolicExtendedExistentialType(NodePointer shapeNode,
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %target-swift-frontend -emit-ir %s -g -target %target-swift-5.9-abi-triple
2+
3+
public protocol P<A, B> {
4+
associatedtype A
5+
associatedtype B
6+
}
7+
8+
public protocol Q<C> {
9+
associatedtype C
10+
}
11+
12+
public protocol R {}
13+
14+
public class C<T: Equatable> {}
15+
16+
public func foo(_ a: any P<Int, Float> & R) {}
17+
public func foo(_ a: any P<Int, Float> & Q<String>) {}
18+
public func foo(_ a: any P<Int, Float> & Q<String> & R) {}
19+
public func foo(_ a: any P<Int, Float> & Q<String> & R & C<Bool>) {}
20+
public func foo(_ a: any P<Int, Float> & Q<String> & R & AnyObject) {}
21+
22+
public func foo(_ a: any (P<Int, Float> & R).Type) {}
23+
public func foo(_ a: any (P<Int, Float> & Q<String>).Type) {}
24+
public func foo(_ a: any (P<Int, Float> & Q<String> & R).Type) {}
25+
public func foo(_ a: any (P<Int, Float> & Q<String> & R & C<Bool>).Type) {}
26+
public func foo(_ a: any (P<Int, Float> & Q<String> & R & AnyObject).Type) {}
27+
28+
public func foo(_ a: (any P<Int, Float> & R).Type) {}
29+
public func foo(_ a: (any P<Int, Float> & Q<String>).Type) {}
30+
public func foo(_ a: (any P<Int, Float> & Q<String> & R).Type) {}
31+
public func foo(_ a: (any P<Int, Float> & Q<String> & R & C<Bool>).Type) {}
32+
public func foo(_ a: (any P<Int, Float> & Q<String> & R & AnyObject).Type) {}
33+
34+
public struct Foo<each T, U> {
35+
public var a1: (repeat any P<each T, U> & R)
36+
}

0 commit comments

Comments
 (0)