Skip to content

Commit f3c0c71

Browse files
authored
Merge pull request #4246 from jckarter/objc-generic-extension-errors-3.0
[3.0] Relax overly conservative "uses generic params" errors in ObjC generic extensions.
2 parents e9cbb6f + a2724fa commit f3c0c71

File tree

4 files changed

+146
-17
lines changed

4 files changed

+146
-17
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: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,29 @@ class FindCapturedVars : public ASTWalker {
7575

7676
// We want to look through type aliases here.
7777
type = type->getCanonicalType();
78-
78+
79+
class TypeCaptureWalker : public TypeWalker {
80+
AnyFunctionRef AFR;
81+
llvm::function_ref<void(Type)> Callback;
82+
public:
83+
explicit TypeCaptureWalker(AnyFunctionRef AFR,
84+
llvm::function_ref<void(Type)> callback)
85+
: AFR(AFR), Callback(callback) {}
86+
87+
Action walkToTypePre(Type ty) override {
88+
Callback(ty);
89+
// Pseudogeneric classes don't use their generic parameters so we
90+
// don't need to visit them.
91+
if (AFR.isObjC()) {
92+
if (auto clas = dyn_cast_or_null<ClassDecl>(ty->getAnyNominal())) {
93+
if (clas->usesObjCGenericsModel()) {
94+
return Action::SkipChildren;
95+
}
96+
}
97+
}
98+
return Action::Continue;
99+
}
100+
};
79101
// If the type contains dynamic 'Self', conservatively assume we will
80102
// need 'Self' metadata at runtime. We could generalize the analysis
81103
// used below for usages of generic parameters in Objective-C
@@ -88,14 +110,14 @@ class FindCapturedVars : public ASTWalker {
88110
// retainable pointer. Similarly stored property access does not
89111
// need it, etc.
90112
if (type->hasDynamicSelfType()) {
91-
type.visit([&](Type t) {
113+
type.walk(TypeCaptureWalker(AFR, [&](Type t) {
92114
if (auto *dynamicSelf = t->getAs<DynamicSelfType>()) {
93115
if (DynamicSelfCaptureLoc.isInvalid()) {
94116
DynamicSelfCaptureLoc = loc;
95117
DynamicSelf = dynamicSelf;
96118
}
97119
}
98-
});
120+
}));
99121
}
100122

101123
// Similar to dynamic 'Self', IRGen doesn't really need type metadata
@@ -106,13 +128,13 @@ class FindCapturedVars : public ASTWalker {
106128
// instead, but even there we don't really have enough information to
107129
// perform it accurately.
108130
if (type->hasArchetype()) {
109-
type.visit([&](Type t) {
131+
type.walk(TypeCaptureWalker(AFR, [&](Type t) {
110132
if (t->is<ArchetypeType>() &&
111133
!t->isOpenedExistential() &&
112134
GenericParamCaptureLoc.isInvalid()) {
113135
GenericParamCaptureLoc = loc;
114136
}
115-
});
137+
}));
116138
}
117139
}
118140

@@ -397,8 +419,10 @@ class FindCapturedVars : public ASTWalker {
397419
// doesn't require its type metadata.
398420
if (auto declRef = dyn_cast<DeclRefExpr>(E))
399421
return (!declRef->getDecl()->isObjC()
400-
&& !E->getType()->hasRetainablePointerRepresentation()
401-
&& !E->getType()->is<AnyMetatypeType>());
422+
&& !E->getType()->getLValueOrInOutObjectType()
423+
->hasRetainablePointerRepresentation()
424+
&& !E->getType()->getLValueOrInOutObjectType()
425+
->is<AnyMetatypeType>());
402426

403427
// Loading classes or metatypes doesn't require their metadata.
404428
if (isa<LoadExpr>(E))
@@ -475,18 +499,43 @@ class FindCapturedVars : public ASTWalker {
475499
if (E->getType()->isObjCExistentialType()
476500
|| E->getType()->is<AnyMetatypeType>())
477501
return false;
502+
503+
// We also special case Any erasure in pseudogeneric contexts
504+
// not to rely on concrete type metadata by erasing from AnyObject
505+
// as a waypoint.
506+
if (E->getType()->isAny()
507+
&& erasure->getSubExpr()->getType()->is<ArchetypeType>())
508+
return false;
509+
478510
// Erasure to a Swift protocol always captures the type metadata from
479511
// its subexpression.
480512
checkType(erasure->getSubExpr()->getType(),
481513
erasure->getSubExpr()->getLoc());
482514
return true;
483515
}
484516

517+
485518
// Converting an @objc metatype to AnyObject doesn't require type
486519
// metadata.
487520
if (isa<ClassMetatypeToObjectExpr>(E)
488521
|| isa<ExistentialMetatypeToObjectExpr>(E))
489522
return false;
523+
524+
// Casting to an ObjC class doesn't require the metadata of its type
525+
// parameters, if any.
526+
if (auto cast = dyn_cast<CheckedCastExpr>(E)) {
527+
if (auto clas = dyn_cast_or_null<ClassDecl>(
528+
cast->getCastTypeLoc().getType()->getAnyNominal())) {
529+
if (clas->usesObjCGenericsModel()) {
530+
return false;
531+
}
532+
}
533+
}
534+
535+
// Assigning an object doesn't require type metadata.
536+
if (auto assignment = dyn_cast<AssignExpr>(E))
537+
return !assignment->getSrc()->getType()
538+
->hasRetainablePointerRepresentation();
490539

491540
return true;
492541
}

test/ClangModules/objc_bridging_generics.swift

Lines changed: 44 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()
@@ -212,6 +210,44 @@ extension AnimalContainer {
212210
y.apexPredator = x
213211
}
214212

213+
func doesntUseGenericParam5(y: T) {
214+
var x = y
215+
x = y
216+
_ = x
217+
}
218+
func doesntUseGenericParam6(y: T?) {
219+
var x = y
220+
x = y
221+
_ = x
222+
}
223+
224+
// Doesn't use 'T', since dynamic casting to an ObjC generic class doesn't
225+
// check its generic parameters
226+
func doesntUseGenericParam7() {
227+
_ = (self as AnyObject) as! GenericClass<T>
228+
_ = (self as AnyObject) as? GenericClass<T>
229+
_ = (self as AnyObject) as! AnimalContainer<T>
230+
_ = (self as AnyObject) as? AnimalContainer<T>
231+
_ = (self as AnyObject) is AnimalContainer<T>
232+
_ = (self as AnyObject) is AnimalContainer<T>
233+
}
234+
235+
// Dynamic casting to the generic parameter would require its generic params,
236+
// though
237+
// expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
238+
func usesGenericParamZ1() {
239+
_ = (self as AnyObject) as! T //expected-note{{here}}
240+
}
241+
// expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
242+
func usesGenericParamZ2() {
243+
_ = (self as AnyObject) as? T //expected-note{{here}}
244+
}
245+
// expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
246+
func usesGenericParamZ3() {
247+
_ = (self as AnyObject) is T //expected-note{{here}}
248+
}
249+
250+
215251
// expected-error@+1{{extension of a generic Objective-C class cannot access the class's generic parameters}}
216252
func usesGenericParamA(_ x: T) {
217253
_ = T(noise: x) // expected-note{{used here}}
@@ -246,9 +282,8 @@ extension AnimalContainer {
246282
}
247283

248284
extension PettableContainer {
249-
// TODO: Any erasure shouldn't use generic parameter metadata.
250-
func doesntUseGenericParam(_ x: T, _ y: T.Type) { // expected-error{{cannot access the class's generic parameters}}
251-
_ = type(of: x).init(fur: x).other() // expected-note{{here}}
285+
func doesntUseGenericParam(_ x: T, _ y: T.Type) {
286+
_ = type(of: x).init(fur: x).other()
252287
_ = type(of: x).adopt().other()
253288
_ = y.init(fur: x).other()
254289
_ = 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)