mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
ASTDemangler: Add support for constrained existential compositions
This commit is contained in:
@@ -767,65 +767,88 @@ Type ASTBuilder::createExistentialMetatypeType(
|
|||||||
Type ASTBuilder::createConstrainedExistentialType(
|
Type ASTBuilder::createConstrainedExistentialType(
|
||||||
Type base, ArrayRef<BuiltRequirement> constraints,
|
Type base, ArrayRef<BuiltRequirement> constraints,
|
||||||
ArrayRef<BuiltInverseRequirement> inverseRequirements) {
|
ArrayRef<BuiltInverseRequirement> inverseRequirements) {
|
||||||
Type constrainedBase;
|
llvm::SmallDenseMap<Identifier, Type> primaryAssociatedTypes;
|
||||||
|
llvm::SmallDenseSet<Identifier> claimed;
|
||||||
|
|
||||||
if (auto baseTy = base->getAs<ProtocolType>()) {
|
|
||||||
auto baseDecl = baseTy->getDecl();
|
|
||||||
llvm::SmallDenseMap<Identifier, Type> cmap;
|
|
||||||
for (const auto &req : constraints) {
|
for (const auto &req : constraints) {
|
||||||
switch (req.getKind()) {
|
switch (req.getKind()) {
|
||||||
case RequirementKind::SameShape:
|
case RequirementKind::SameShape:
|
||||||
llvm_unreachable("Same-shape requirement not supported here");
|
|
||||||
case RequirementKind::Conformance:
|
case RequirementKind::Conformance:
|
||||||
case RequirementKind::Superclass:
|
case RequirementKind::Superclass:
|
||||||
case RequirementKind::Layout:
|
case RequirementKind::Layout:
|
||||||
continue;
|
break;
|
||||||
|
|
||||||
case RequirementKind::SameType:
|
case RequirementKind::SameType: {
|
||||||
if (auto *DMT = req.getFirstType()->getAs<DependentMemberType>())
|
if (auto *memberTy = req.getFirstType()->getAs<DependentMemberType>()) {
|
||||||
cmap[DMT->getName()] = req.getSecondType();
|
if (memberTy->getBase()->is<GenericTypeParamType>()) {
|
||||||
|
// This is the only case we understand so far.
|
||||||
|
primaryAssociatedTypes[memberTy->getName()] = req.getSecondType();
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
llvm::SmallVector<Type, 4> args;
|
break;
|
||||||
for (auto *assocTy : baseDecl->getPrimaryAssociatedTypes()) {
|
}
|
||||||
auto argTy = cmap.find(assocTy->getName());
|
}
|
||||||
if (argTy == cmap.end()) {
|
|
||||||
|
// If we end here, we didn't recognize this requirement.
|
||||||
return Type();
|
return Type();
|
||||||
}
|
}
|
||||||
args.push_back(argTy->getSecond());
|
|
||||||
|
auto maybeFormParameterizedProtocolType = [&](ProtocolType *protoTy) -> Type {
|
||||||
|
auto *proto = protoTy->getDecl();
|
||||||
|
|
||||||
|
llvm::SmallVector<Type, 4> args;
|
||||||
|
for (auto *assocTy : proto->getPrimaryAssociatedTypes()) {
|
||||||
|
auto found = primaryAssociatedTypes.find(assocTy->getName());
|
||||||
|
if (found == primaryAssociatedTypes.end())
|
||||||
|
return protoTy;
|
||||||
|
args.push_back(found->second);
|
||||||
|
claimed.insert(found->first);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We may not have any arguments because the constrained existential is a
|
// We may not have any arguments because the constrained existential is a
|
||||||
// plain protocol with an inverse requirement.
|
// plain protocol with an inverse requirement.
|
||||||
if (args.empty()) {
|
if (args.empty())
|
||||||
constrainedBase =
|
return protoTy;
|
||||||
ProtocolType::get(baseDecl, baseTy, base->getASTContext());
|
|
||||||
|
return ParameterizedProtocolType::get(Ctx, protoTy, args);
|
||||||
|
};
|
||||||
|
|
||||||
|
SmallVector<Type, 2> members;
|
||||||
|
bool hasExplicitAnyObject = false;
|
||||||
|
InvertibleProtocolSet inverses;
|
||||||
|
|
||||||
|
// We're given either a single protocol type, or a composition of protocol
|
||||||
|
// types. Transform each protocol type to add arguments, if necessary.
|
||||||
|
if (auto protoTy = base->getAs<ProtocolType>()) {
|
||||||
|
members.push_back(maybeFormParameterizedProtocolType(protoTy));
|
||||||
} else {
|
} else {
|
||||||
constrainedBase =
|
auto compositionTy = base->castTo<ProtocolCompositionType>();
|
||||||
ParameterizedProtocolType::get(base->getASTContext(), baseTy, args);
|
hasExplicitAnyObject = compositionTy->hasExplicitAnyObject();
|
||||||
|
ASSERT(compositionTy->getInverses().empty());
|
||||||
|
|
||||||
|
for (auto member : compositionTy->getMembers()) {
|
||||||
|
if (auto *protoTy = member->getAs<ProtocolType>()) {
|
||||||
|
members.push_back(maybeFormParameterizedProtocolType(protoTy));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ASSERT(member->getClassOrBoundGenericClass());
|
||||||
|
members.push_back(member);
|
||||||
}
|
}
|
||||||
} else if (base->isAny()) {
|
|
||||||
// The only other case should be that we got an empty PCT, which is equal to
|
|
||||||
// the Any type. The other constraints should have been encoded in the
|
|
||||||
// existential's generic signature (and arrive as BuiltInverseRequirement).
|
|
||||||
constrainedBase = base;
|
|
||||||
} else {
|
|
||||||
return Type();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(constrainedBase);
|
// Make sure that all arguments were actually used.
|
||||||
|
ASSERT(claimed.size() == primaryAssociatedTypes.size());
|
||||||
|
|
||||||
// Handle inverse requirements.
|
// Handle inverse requirements.
|
||||||
if (!inverseRequirements.empty()) {
|
if (!inverseRequirements.empty()) {
|
||||||
InvertibleProtocolSet inverseSet;
|
|
||||||
for (const auto &inverseReq : inverseRequirements) {
|
for (const auto &inverseReq : inverseRequirements) {
|
||||||
inverseSet.insert(inverseReq.getKind());
|
inverses.insert(inverseReq.getKind());
|
||||||
}
|
}
|
||||||
constrainedBase = ProtocolCompositionType::get(
|
|
||||||
Ctx, { constrainedBase }, inverseSet, /*hasExplicitAnyObject=*/false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ExistentialType::get(constrainedBase);
|
return ExistentialType::get(ProtocolCompositionType::get(
|
||||||
|
Ctx, members, inverses, hasExplicitAnyObject));
|
||||||
}
|
}
|
||||||
|
|
||||||
Type ASTBuilder::createSymbolicExtendedExistentialType(NodePointer shapeNode,
|
Type ASTBuilder::createSymbolicExtendedExistentialType(NodePointer shapeNode,
|
||||||
|
|||||||
36
test/DebugInfo/parameterized_existential_composition.swift
Normal file
36
test/DebugInfo/parameterized_existential_composition.swift
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// RUN: %target-swift-frontend -emit-ir %s -g -target %target-swift-5.9-abi-triple
|
||||||
|
|
||||||
|
public protocol P<A, B> {
|
||||||
|
associatedtype A
|
||||||
|
associatedtype B
|
||||||
|
}
|
||||||
|
|
||||||
|
public protocol Q<C> {
|
||||||
|
associatedtype C
|
||||||
|
}
|
||||||
|
|
||||||
|
public protocol R {}
|
||||||
|
|
||||||
|
public class C<T: Equatable> {}
|
||||||
|
|
||||||
|
public func foo(_ a: any P<Int, Float> & R) {}
|
||||||
|
public func foo(_ a: any P<Int, Float> & Q<String>) {}
|
||||||
|
public func foo(_ a: any P<Int, Float> & Q<String> & R) {}
|
||||||
|
public func foo(_ a: any P<Int, Float> & Q<String> & R & C<Bool>) {}
|
||||||
|
public func foo(_ a: any P<Int, Float> & Q<String> & R & AnyObject) {}
|
||||||
|
|
||||||
|
public func foo(_ a: any (P<Int, Float> & R).Type) {}
|
||||||
|
public func foo(_ a: any (P<Int, Float> & Q<String>).Type) {}
|
||||||
|
public func foo(_ a: any (P<Int, Float> & Q<String> & R).Type) {}
|
||||||
|
public func foo(_ a: any (P<Int, Float> & Q<String> & R & C<Bool>).Type) {}
|
||||||
|
public func foo(_ a: any (P<Int, Float> & Q<String> & R & AnyObject).Type) {}
|
||||||
|
|
||||||
|
public func foo(_ a: (any P<Int, Float> & R).Type) {}
|
||||||
|
public func foo(_ a: (any P<Int, Float> & Q<String>).Type) {}
|
||||||
|
public func foo(_ a: (any P<Int, Float> & Q<String> & R).Type) {}
|
||||||
|
public func foo(_ a: (any P<Int, Float> & Q<String> & R & C<Bool>).Type) {}
|
||||||
|
public func foo(_ a: (any P<Int, Float> & Q<String> & R & AnyObject).Type) {}
|
||||||
|
|
||||||
|
public struct Foo<each T, U> {
|
||||||
|
public var a1: (repeat any P<each T, U> & R)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user