Skip to content

Commit fdbad84

Browse files
committed
Sema/SILGen: Do erasure from pseudogeneric T to Any without requiring runtime metadata.
Naively wrapping a T in an Any would require metadata for T, but we can go to AnyObject first and put the AnyObject in the Any without T's metadata. This fixes a regression in ObjC generic extension methods when they try to pass their generic parameters to id parameters as Any. rdar://problem/27526877
1 parent 0be4aff commit fdbad84

File tree

4 files changed

+61
-10
lines changed

4 files changed

+61
-10
lines changed

lib/SILGen/SILGenConvert.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,40 @@ ManagedValue SILGenFunction::emitExistentialErasure(
654654
return emitManagedRValueWithCleanup(existential);
655655
}
656656
case ExistentialRepresentation::Opaque: {
657+
658+
// If the concrete value is a pseudogeneric archetype, first erase it to
659+
// its upper bound.
660+
auto anyObjectProto = getASTContext()
661+
.getProtocol(KnownProtocolKind::AnyObject);
662+
auto anyObjectTy = anyObjectProto
663+
? anyObjectProto->getDeclaredType()->getCanonicalType()
664+
: CanType();
665+
auto eraseToAnyObject =
666+
[&, concreteFormalType, F](SGFContext C) -> ManagedValue {
667+
auto concreteValue = F(SGFContext());
668+
auto anyObjectConformance = SGM.SwiftModule
669+
->lookupConformance(concreteFormalType, anyObjectProto, nullptr);
670+
ProtocolConformanceRef buf[] = {
671+
*anyObjectConformance,
672+
};
673+
674+
auto asAnyObject = B.createInitExistentialRef(loc,
675+
SILType::getPrimitiveObjectType(anyObjectTy),
676+
concreteFormalType,
677+
concreteValue.getValue(),
678+
getASTContext().AllocateCopy(buf));
679+
return ManagedValue(asAnyObject, concreteValue.getCleanup());
680+
};
681+
682+
auto concreteTLPtr = &concreteTL;
683+
if (this->F.getLoweredFunctionType()->isPseudogeneric()) {
684+
if (anyObjectTy && concreteFormalType->is<ArchetypeType>()) {
685+
concreteFormalType = anyObjectTy;
686+
concreteTLPtr = &getTypeLowering(anyObjectTy);
687+
F = eraseToAnyObject;
688+
}
689+
}
690+
657691
// Allocate the existential.
658692
SILValue existential =
659693
getBufferForExprResult(loc, existentialTL.getLoweredType(), C);
@@ -662,7 +696,7 @@ ManagedValue SILGenFunction::emitExistentialErasure(
662696
SILValue valueAddr = B.createInitExistentialAddr(
663697
loc, existential,
664698
concreteFormalType,
665-
concreteTL.getLoweredType(),
699+
concreteTLPtr->getLoweredType(),
666700
conformances);
667701
// Initialize the concrete value in-place.
668702
InitializationPtr init(

lib/Sema/TypeCheckCaptures.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,13 +477,22 @@ class FindCapturedVars : public ASTWalker {
477477
if (E->getType()->isObjCExistentialType()
478478
|| E->getType()->is<AnyMetatypeType>())
479479
return false;
480+
481+
// We also special case Any erasure in pseudogeneric contexts
482+
// not to rely on concrete type metadata by erasing from AnyObject
483+
// as a waypoint.
484+
if (E->getType()->isAny()
485+
&& erasure->getSubExpr()->getType()->is<ArchetypeType>())
486+
return false;
487+
480488
// Erasure to a Swift protocol always captures the type metadata from
481489
// its subexpression.
482490
checkType(erasure->getSubExpr()->getType(),
483491
erasure->getSubExpr()->getLoc());
484492
return true;
485493
}
486494

495+
487496
// Converting an @objc metatype to AnyObject doesn't require type
488497
// metadata.
489498
if (isa<ClassMetatypeToObjectExpr>(E)

test/ClangModules/objc_bridging_generics.swift

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,8 @@ extension GenericClass {
133133
func usesGenericParamG(_ x: T) {
134134
_ = T.self // expected-note{{used here}}
135135
}
136-
// expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
137-
func usesGenericParamH(_ x: T) {
138-
_ = x as Any // expected-note{{used here}}
136+
func doesntUseGenericParamH(_ x: T) {
137+
_ = x as Any
139138
}
140139
// expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
141140
func usesGenericParamI(_ y: T.Type) {
@@ -181,14 +180,13 @@ extension AnimalContainer {
181180
_ = #selector(y.create)
182181
}
183182

184-
// TODO: 'Any' bridging should not require reifying generic params.
185-
func doesntUseGenericParam2(_ x: T, _ y: T.Type) { // expected-error{{cannot access the class's generic parameters}}
183+
func doesntUseGenericParam2(_ x: T, _ y: T.Type) {
186184
let a = x.another()
187185
_ = a.another()
188186
_ = x.another().another()
189187

190188
_ = type(of: x).create().another()
191-
_ = type(of: x).init(noise: x).another() // expected-note{{here}}
189+
_ = type(of: x).init(noise: x).another()
192190
_ = y.create().another()
193191
_ = y.init(noise: x).another()
194192
_ = y.init(noise: x.another()).another()
@@ -257,9 +255,8 @@ extension AnimalContainer {
257255
}
258256

259257
extension PettableContainer {
260-
// TODO: Any erasure shouldn't use generic parameter metadata.
261-
func doesntUseGenericParam(_ x: T, _ y: T.Type) { // expected-error{{cannot access the class's generic parameters}}
262-
_ = type(of: x).init(fur: x).other() // expected-note{{here}}
258+
func doesntUseGenericParam(_ x: T, _ y: T.Type) {
259+
_ = type(of: x).init(fur: x).other()
263260
_ = type(of: x).adopt().other()
264261
_ = y.init(fur: x).other()
265262
_ = y.adopt().other()

test/SILGen/objc_bridging_any.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// REQUIRES: objc_interop
33

44
import Foundation
5+
import objc_generics
56

67
protocol P {}
78
protocol CP: class {}
@@ -498,3 +499,13 @@ func dynamicLookup(x: AnyObject) {
498499
_ = x.anyProperty
499500
_ = x[IndexForAnySubscript()]
500501
}
502+
503+
extension GenericClass {
504+
// CHECK-LABEL: sil hidden @_TFE17objc_bridging_anyCSo12GenericClass23pseudogenericAnyErasurefT1xx_P_
505+
func pseudogenericAnyErasure(x: T) -> Any {
506+
// CHECK: [[ANY_BUF:%.*]] = init_existential_addr %0 : $*Any, $AnyObject
507+
// CHECK: [[ANYOBJECT:%.*]] = init_existential_ref %1 : $T : $T, $AnyObject
508+
// CHECK: store [[ANYOBJECT]] to [[ANY_BUF]]
509+
return x
510+
}
511+
}

0 commit comments

Comments
 (0)