Skip to content

Commit 061eaed

Browse files
authored
Merge pull request #72808 from slavapestov/fix-existential-metatype-to-any-6.0
[6.0] Sema: Fix existential-metatype-to-Any conversion
2 parents 1dfa342 + d30c107 commit 061eaed

File tree

11 files changed

+118
-69
lines changed

11 files changed

+118
-69
lines changed

include/swift/AST/Type.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -126,17 +126,6 @@ class MakeAbstractConformanceForGenericType {
126126
ProtocolDecl *conformedProtocol) const;
127127
};
128128

129-
/// Functor class suitable for use as a \c LookupConformanceFn that provides
130-
/// only abstract conformances, or builtin conformances for invertible protocols
131-
/// for generic types. Asserts that the replacement
132-
/// type is an opaque generic type.
133-
class MakeAbstractOrBuiltinConformanceForGenericType {
134-
public:
135-
ProtocolConformanceRef operator()(CanType dependentType,
136-
Type conformingReplacementType,
137-
ProtocolDecl *conformedProtocol) const;
138-
};
139-
140129
/// Functor class suitable for use as a \c LookupConformanceFn that fetches
141130
/// conformances from a generic signature.
142131
class LookUpConformanceInSignature {

include/swift/SIL/SILCloner.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
196196
// If we found a type containing a local archetype, substitute
197197
// open existentials throughout the substitution map.
198198
Subs = Subs.subst(QueryTypeSubstitutionMapOrIdentity{LocalArchetypeSubs},
199-
MakeAbstractOrBuiltinConformanceForGenericType());
199+
MakeAbstractConformanceForGenericType());
200200
}
201201
}
202202

@@ -219,7 +219,7 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
219219
return Ty.subst(
220220
Builder.getModule(),
221221
QueryTypeSubstitutionMapOrIdentity{LocalArchetypeSubs},
222-
MakeAbstractOrBuiltinConformanceForGenericType(),
222+
MakeAbstractConformanceForGenericType(),
223223
CanGenericSignature());
224224
}
225225
SILType getOpType(SILType Ty) {
@@ -239,7 +239,7 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
239239

240240
return ty.subst(
241241
QueryTypeSubstitutionMapOrIdentity{LocalArchetypeSubs},
242-
MakeAbstractOrBuiltinConformanceForGenericType()
242+
MakeAbstractConformanceForGenericType()
243243
)->getCanonicalType();
244244
}
245245

@@ -352,7 +352,7 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
352352
conformance.subst(ty,
353353
QueryTypeSubstitutionMapOrIdentity{
354354
LocalArchetypeSubs},
355-
MakeAbstractOrBuiltinConformanceForGenericType());
355+
MakeAbstractConformanceForGenericType());
356356
}
357357

358358
return asImpl().remapConformance(getASTTypeInClonedContext(ty),

lib/AST/SubstitutionMap.cpp

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -355,16 +355,6 @@ SubstitutionMap::lookupConformance(CanType type, ProtocolDecl *proto) const {
355355
if (!type->isTypeParameter())
356356
return ProtocolConformanceRef::forInvalid();
357357

358-
// If the protocol is invertible, just do a global lookup. This avoids an
359-
// infinite substitution issue by recognizing that these protocols are
360-
// very simple (see rdar://119950540 for the general issue).
361-
if (proto->getInvertibleProtocolKind()) {
362-
auto substType = type.subst(*this);
363-
if (!substType->isTypeParameter())
364-
return proto->getModuleContext()->lookupConformance(substType, proto);
365-
return ProtocolConformanceRef(proto);
366-
}
367-
368358
auto genericSig = getGenericSignature();
369359

370360
auto getSignatureConformance =
@@ -396,6 +386,15 @@ SubstitutionMap::lookupConformance(CanType type, ProtocolDecl *proto) const {
396386
return ProtocolConformanceRef::forMissingOrInvalid(substType, proto);
397387
}
398388

389+
// If the protocol is invertible, fall back to a global lookup instead of
390+
// evaluating a conformance path, to avoid an infinite substitution issue.
391+
if (proto->getInvertibleProtocolKind()) {
392+
auto substType = type.subst(*this);
393+
if (!substType->isTypeParameter())
394+
return proto->getModuleContext()->lookupConformance(substType, proto);
395+
return ProtocolConformanceRef(proto);
396+
}
397+
399398
auto path = genericSig->getConformancePath(type, proto);
400399

401400
ProtocolConformanceRef conformance;

lib/AST/TypeSubstitution.cpp

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -230,22 +230,6 @@ operator()(CanType dependentType, Type conformingReplacementType,
230230
return Subs.lookupConformance(dependentType, conformedProtocol);
231231
}
232232

233-
ProtocolConformanceRef MakeAbstractOrBuiltinConformanceForGenericType::
234-
operator()(CanType dependentType, Type conformingReplacementType,
235-
ProtocolDecl *conformedProtocol) const {
236-
// Workaround for rdar://125460667
237-
if (conformedProtocol->getInvertibleProtocolKind()) {
238-
auto &ctx = conformedProtocol->getASTContext();
239-
return ProtocolConformanceRef(
240-
ctx.getBuiltinConformance(conformingReplacementType, conformedProtocol,
241-
BuiltinConformanceKind::Synthesized));
242-
}
243-
244-
return MakeAbstractConformanceForGenericType()(dependentType,
245-
conformingReplacementType,
246-
conformedProtocol);
247-
}
248-
249233
ProtocolConformanceRef MakeAbstractConformanceForGenericType::
250234
operator()(CanType dependentType, Type conformingReplacementType,
251235
ProtocolDecl *conformedProtocol) const {

lib/SIL/IR/SILInstructions.cpp

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2185,14 +2185,24 @@ ObjCMethodInst::create(SILDebugLocation DebugLoc, SILValue Operand,
21852185
Member, Ty);
21862186
}
21872187

2188+
static void checkExistentialPreconditions(SILType ExistentialType,
2189+
CanType ConcreteType,
2190+
ArrayRef<ProtocolConformanceRef> Conformances) {
2191+
#ifndef NDEBUG
2192+
auto layout = ExistentialType.getASTType().getExistentialLayout();
2193+
assert(layout.getProtocols().size() == Conformances.size());
2194+
2195+
for (auto conformance : Conformances) {
2196+
assert(!conformance.isAbstract() || isa<ArchetypeType>(ConcreteType));
2197+
}
2198+
#endif
2199+
}
2200+
21882201
InitExistentialAddrInst *InitExistentialAddrInst::create(
21892202
SILDebugLocation Loc, SILValue Existential, CanType ConcreteType,
21902203
SILType ConcreteLoweredType, ArrayRef<ProtocolConformanceRef> Conformances,
21912204
SILFunction *F) {
2192-
#ifndef NDEBUG
2193-
auto layout = Existential->getType().getASTType().getExistentialLayout();
2194-
assert(layout.getProtocols().size() == Conformances.size());
2195-
#endif
2205+
checkExistentialPreconditions(Existential->getType(), ConcreteType, Conformances);
21962206

21972207
SILModule &Mod = F->getModule();
21982208
SmallVector<SILValue, 8> TypeDependentOperands;
@@ -2212,10 +2222,7 @@ InitExistentialValueInst *InitExistentialValueInst::create(
22122222
SILDebugLocation Loc, SILType ExistentialType, CanType ConcreteType,
22132223
SILValue Instance, ArrayRef<ProtocolConformanceRef> Conformances,
22142224
SILFunction *F) {
2215-
#ifndef NDEBUG
2216-
auto layout = ExistentialType.getASTType().getExistentialLayout();
2217-
assert(layout.getProtocols().size() == Conformances.size());
2218-
#endif
2225+
checkExistentialPreconditions(ExistentialType, ConcreteType, Conformances);
22192226

22202227
SILModule &Mod = F->getModule();
22212228
SmallVector<SILValue, 8> TypeDependentOperands;
@@ -2233,10 +2240,7 @@ InitExistentialRefInst *InitExistentialRefInst::create(
22332240
SILDebugLocation Loc, SILType ExistentialType, CanType ConcreteType,
22342241
SILValue Instance, ArrayRef<ProtocolConformanceRef> Conformances,
22352242
SILFunction *F, ValueOwnershipKind forwardingOwnershipKind) {
2236-
#ifndef NDEBUG
2237-
auto layout = ExistentialType.getASTType().getExistentialLayout();
2238-
assert(layout.getProtocols().size() == Conformances.size());
2239-
#endif
2243+
checkExistentialPreconditions(ExistentialType, ConcreteType, Conformances);
22402244

22412245
SILModule &Mod = F->getModule();
22422246
SmallVector<SILValue, 8> TypeDependentOperands;

lib/SILGen/SILGenConvert.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -833,9 +833,6 @@ ManagedValue SILGenFunction::emitExistentialErasure(
833833
[&, concreteFormalType, F](SGFContext C) -> ManagedValue {
834834
auto concreteValue = F(SGFContext());
835835
assert(concreteFormalType->isBridgeableObjectType());
836-
auto *M = SGM.M.getSwiftModule();
837-
auto conformances = M->collectExistentialConformances(
838-
concreteFormalType, anyObjectTy);
839836
return B.createInitExistentialRef(
840837
loc, SILType::getPrimitiveObjectType(anyObjectTy), concreteFormalType,
841838
concreteValue, conformances);
@@ -844,6 +841,12 @@ ManagedValue SILGenFunction::emitExistentialErasure(
844841
if (this->F.getLoweredFunctionType()->isPseudogeneric()) {
845842
if (anyObjectTy && concreteFormalType->is<ArchetypeType>()) {
846843
concreteFormalType = anyObjectTy;
844+
845+
// The original conformances are no good because they have the wrong
846+
// (pseudogeneric) subject type.
847+
auto *M = SGM.M.getSwiftModule();
848+
conformances = M->collectExistentialConformances(
849+
concreteFormalType, anyObjectTy);
847850
F = eraseToAnyObject;
848851
}
849852
}

lib/Sema/CSApply.cpp

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6688,13 +6688,24 @@ Expr *ExprRewriter::coerceExistential(Expr *expr, Type toType,
66886688
Type fromInstanceType = fromType;
66896689
Type toInstanceType = toType;
66906690

6691-
// Look through metatypes
6691+
// For existential-to-existential coercions, open the source existential.
6692+
Type openedFromType;
6693+
if (fromType->isAnyExistentialType()) {
6694+
openedFromType = OpenedArchetypeType::getAny(fromType->getCanonicalType(),
6695+
dc->getGenericSignatureOfContext());
6696+
}
6697+
6698+
Type openedFromInstanceType = openedFromType;
6699+
6700+
// Look through metatypes.
66926701
while ((fromInstanceType->is<UnresolvedType>() ||
66936702
fromInstanceType->is<AnyMetatypeType>()) &&
66946703
toInstanceType->is<ExistentialMetatypeType>()) {
66956704
if (!fromInstanceType->is<UnresolvedType>())
6696-
fromInstanceType = fromInstanceType->castTo<AnyMetatypeType>()->getInstanceType();
6697-
toInstanceType = toInstanceType->castTo<ExistentialMetatypeType>()->getExistentialInstanceType();
6705+
fromInstanceType = fromInstanceType->getMetatypeInstanceType();
6706+
if (openedFromInstanceType && !openedFromInstanceType->is<UnresolvedType>())
6707+
openedFromInstanceType = openedFromInstanceType->getMetatypeInstanceType();
6708+
toInstanceType = toInstanceType->getMetatypeInstanceType();
66986709
}
66996710

67006711
ASTContext &ctx = cs.getASTContext();
@@ -6758,20 +6769,13 @@ Expr *ExprRewriter::coerceExistential(Expr *expr, Type toType,
67586769
}
67596770

67606771
// For existential-to-existential coercions, open the source existential.
6761-
if (fromType->isAnyExistentialType()) {
6762-
fromType = OpenedArchetypeType::getAny(fromType->getCanonicalType(),
6763-
dc->getGenericSignatureOfContext());
6764-
6772+
if (openedFromType) {
67656773
auto *archetypeVal = cs.cacheType(
6766-
new (ctx) OpaqueValueExpr(expr->getSourceRange(), fromType));
6767-
6768-
fromInstanceType = fromType;
6769-
while (auto *metatypeType = fromInstanceType->getAs<MetatypeType>())
6770-
fromInstanceType = metatypeType->getInstanceType();
6774+
new (ctx) OpaqueValueExpr(expr->getSourceRange(), openedFromType));
67716775

67726776
auto conformances =
67736777
dc->getParentModule()
6774-
->collectExistentialConformances(fromInstanceType->getCanonicalType(),
6778+
->collectExistentialConformances(openedFromInstanceType->getCanonicalType(),
67756779
toInstanceType->getCanonicalType(),
67766780
/*allowMissing=*/true);
67776781

test/Generics/rdar124697829.swift

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: %target-swift-frontend -emit-ir %s -disable-availability-checking
2+
3+
// This is a generics test, but only IRGen exercised the substitution of
4+
// an abstract conformance with a type parameter -- in the type checker and
5+
// SIL, we only deal with archetypes.
6+
7+
public protocol IteratorProtocol {
8+
associatedtype Element
9+
}
10+
11+
public protocol Sequence {
12+
associatedtype Iterator: IteratorProtocol
13+
associatedtype Element where Element == Iterator.Element
14+
}
15+
16+
public struct IndexingIterator<S: Sequence>: IteratorProtocol {
17+
public typealias Element = S.Element
18+
}
19+
20+
public struct Array<Element>: Sequence {
21+
public typealias Iterator = IndexingIterator<Self>
22+
}
23+
24+
public protocol Publisher {
25+
associatedtype Output
26+
}
27+
28+
public struct SequencePublisher<Elements: Sequence>: Publisher {
29+
public typealias Output = Elements.Element
30+
}
31+
32+
public struct Map<Pub: Publisher, Output>: Publisher {}
33+
34+
public func foo<T>(_: T) -> some Publisher {
35+
bar(SequencePublisher<Array<T>>())
36+
}
37+
38+
public func bar<Pub: Publisher>(_: Pub) -> some Publisher {
39+
Map<Pub, Pub.Output>()
40+
}
41+

test/SILOptimizer/rdar125460667.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %target-swift-frontend -emit-sil %s
2+
3+
@_transparent func f(a: Any.Type) -> Any {
4+
return a
5+
}
6+
7+
func g(a: Any.Type) {
8+
f(a: a)
9+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public protocol P1 {
2+
associatedtype A: Sendable
3+
}
4+
5+
public protocol P2: P1, Sendable where A == any P2 {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module %S/Inputs/protocol_with_self_conforming_existential_other.swift -emit-module-path %t/protocol_with_self_conforming_existential_other.swiftmodule
3+
// RUN: %target-swift-frontend -emit-silgen %s -I %t
4+
5+
import protocol_with_self_conforming_existential_other
6+
7+
// Declare a type conforming to P2, to force deserializing its
8+
// requirement signature.
9+
10+
struct MyP2: P2 {}
11+

0 commit comments

Comments
 (0)