Skip to content

Commit c165509

Browse files
committed
Correctly emit inverse proto comps with extended shape symbolic refs
1 parent 0083f09 commit c165509

File tree

6 files changed

+48
-42
lines changed

6 files changed

+48
-42
lines changed

include/swift/AST/ExistentialLayout.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,20 @@ struct ExistentialLayout {
117117

118118
LayoutConstraint getLayoutConstraint() const;
119119

120+
/// Whether this layout has any inverses within its signature.
121+
bool hasInverses() const {
122+
return !inverses.empty();
123+
}
124+
125+
/// Whether this existential needs to have an extended existential shape. This
126+
/// is relevant for the mangler to mangle as a symbolic link where possible
127+
/// and for IRGen directly emitting some existentials.
128+
bool needsExtendedShape() const;
129+
120130
private:
121131
SmallVector<ProtocolDecl *, 4> protocols;
122132
SmallVector<ParameterizedProtocolType *, 4> parameterized;
133+
InvertibleProtocolSet inverses;
123134
};
124135

125136
}

lib/AST/ASTMangler.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1613,7 +1613,7 @@ void ASTMangler::appendType(Type type, GenericSignature sig,
16131613
// ExtendedExistentialTypeShapes consider existential metatypes to
16141614
// be part of the existential, so if we're symbolically referencing
16151615
// shapes, we need to handle that at this level.
1616-
if (EMT->hasParameterizedExistential()) {
1616+
if (EMT->getExistentialLayout().needsExtendedShape()) {
16171617
auto referent = SymbolicReferent::forExtendedExistentialTypeShape(EMT);
16181618
if (canSymbolicReference(referent)) {
16191619
appendSymbolicExtendedExistentialType(referent, EMT, sig, forDecl);
@@ -1693,7 +1693,7 @@ void ASTMangler::appendType(Type type, GenericSignature sig,
16931693

16941694
case TypeKind::Existential: {
16951695
auto *ET = cast<ExistentialType>(tybase);
1696-
if (ET->hasParameterizedExistential()) {
1696+
if (ET->getExistentialLayout().needsExtendedShape()) {
16971697
auto referent = SymbolicReferent::forExtendedExistentialTypeShape(ET);
16981698
if (canSymbolicReference(referent)) {
16991699
appendSymbolicExtendedExistentialType(referent, ET, sig, forDecl);

lib/AST/Type.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,8 @@ ExistentialLayout::ExistentialLayout(CanProtocolType type) {
320320
!protoDecl->isMarkerProtocol());
321321
representsAnyObject = false;
322322

323+
inverses = InvertibleProtocolSet();
324+
323325
protocols.push_back(protoDecl);
324326
expandDefaults(protocols, InvertibleProtocolSet(), type->getASTContext());
325327
}
@@ -353,7 +355,7 @@ ExistentialLayout::ExistentialLayout(CanProtocolCompositionType type) {
353355
protocols.push_back(protoDecl);
354356
}
355357

356-
auto inverses = type->getInverses();
358+
inverses = type->getInverses();
357359
expandDefaults(protocols, inverses, type->getASTContext());
358360

359361
representsAnyObject = [&]() {
@@ -433,6 +435,16 @@ Type ExistentialLayout::getSuperclass() const {
433435
return Type();
434436
}
435437

438+
bool ExistentialLayout::needsExtendedShape() const {
439+
if (!getParameterizedProtocols().empty())
440+
return true;
441+
442+
if (hasInverses())
443+
return true;
444+
445+
return false;
446+
}
447+
436448
bool TypeBase::isObjCExistentialType() {
437449
return getCanonicalType().isObjCExistentialType();
438450
}

lib/IRGen/GenMeta.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7852,8 +7852,10 @@ irgen::emitExtendedExistentialTypeShape(IRGenModule &IGM,
78527852

78537853
// You can have a superclass with a generic parameter pack in a composition,
78547854
// like `C<each T> & P<Int>`
7855-
assert(genHeader->GenericPackArguments.empty() &&
7855+
if (genSig) {
7856+
assert(genHeader->GenericPackArguments.empty() &&
78567857
"Generic parameter packs not supported here yet");
7858+
}
78577859

78587860
return b.finishAndCreateFuture();
78597861
}, [&](llvm::GlobalVariable *var) {

lib/IRGen/MetadataRequest.cpp

Lines changed: 3 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -264,41 +264,6 @@ MetadataDependency MetadataDependencyCollector::finish(IRGenFunction &IGF) {
264264
return result;
265265
}
266266

267-
static bool usesExtendedExistentialMetadata(CanType type) {
268-
auto layout = type.getExistentialLayout();
269-
// If there are parameterized protocol types that we want to
270-
// treat as equal to unparameterized protocol types (maybe
271-
// something like `P<some Any>`?), then AST type canonicalization
272-
// should turn them into unparameterized protocol types. If the
273-
// structure makes it to IRGen, we have to honor that decision that
274-
// they represent different types.
275-
return !layout.getParameterizedProtocols().empty();
276-
}
277-
278-
static std::optional<std::pair<CanExistentialType, /*depth*/ unsigned>>
279-
usesExtendedExistentialMetadata(CanExistentialMetatypeType type) {
280-
unsigned depth = 1;
281-
auto cur = type.getInstanceType();
282-
while (auto metatype = dyn_cast<ExistentialMetatypeType>(cur)) {
283-
cur = metatype.getInstanceType();
284-
depth++;
285-
}
286-
287-
// The only existential types that don't currently use ExistentialType
288-
// are Any and AnyObject, which don't use extended metadata.
289-
if (usesExtendedExistentialMetadata(cur)) {
290-
// HACK: The AST for an existential metatype of a (parameterized) protocol
291-
// still directly wraps the existential type as its instance, which means
292-
// we need to reconstitute the enclosing ExistentialType.
293-
assert(cur->isExistentialType());
294-
if (!cur->is<ExistentialType>()) {
295-
cur = ExistentialType::get(cur)->getCanonicalType();
296-
}
297-
return std::make_pair(cast<ExistentialType>(cur), depth);
298-
}
299-
return std::nullopt;
300-
}
301-
302267
llvm::Constant *IRGenModule::getAddrOfStringForMetadataRef(
303268
StringRef symbolName,
304269
unsigned alignment,
@@ -1998,7 +1963,7 @@ namespace {
19981963

19991964
// Existential metatypes for extended existentials don't use
20001965
// ExistentialMetatypeMetadata.
2001-
if (usesExtendedExistentialMetadata(type)) {
1966+
if (type->getExistentialLayout().needsExtendedShape()) {
20021967
auto metadata = emitExtendedExistentialTypeMetadata(type);
20031968
return setLocal(type, MetadataResponse::forComplete(metadata));
20041969
}
@@ -3110,8 +3075,8 @@ static bool shouldAccessByMangledName(IRGenModule &IGM, CanType type) {
31103075
void visitExistentialMetatypeType(CanExistentialMetatypeType meta) {
31113076
// Extended existential metatypes just emit a different shape
31123077
// and don't do any wrapping.
3113-
if (auto typeAndDepth = usesExtendedExistentialMetadata(meta)) {
3114-
return visit(typeAndDepth.first);
3078+
if (meta->getExistentialLayout().needsExtendedShape()) {
3079+
// return visit(unwrapExistentialMetatype(meta));
31153080
}
31163081

31173082
// The number of accesses turns out the same as the instance type,

test/Interpreter/moveonly_existentials.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,19 @@ func mutate(_ b: inout any Boopable & ~Copyable) {
2828
borrow(S())
2929
var s = S() as any Boopable & ~Copyable
3030
mutate(&s)
31+
32+
let a: Any = (any ~Copyable).self
33+
// CHECK: << invalid type >>
34+
print(a)
35+
36+
let b: Any = (any ~Escapable).self
37+
// CHECK: << invalid type >>
38+
print(b)
39+
40+
let c: Any = (any ~Copyable & ~Escapable).self
41+
// CHECK: << invalid type >>
42+
print(c)
43+
44+
let d: Any = (any Boopable & ~Copyable).self
45+
// CHECK: << invalid type >>
46+
print(d)

0 commit comments

Comments
 (0)