Skip to content

Commit 2af7041

Browse files
committed
Merge pull request #2210 from jckarter/objc-extension-generic-params
2 parents a91becc + f4765f6 commit 2af7041

File tree

7 files changed

+404
-63
lines changed

7 files changed

+404
-63
lines changed

include/swift/AST/AnyFunctionRef.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,26 @@ class AnyFunctionRef {
137137
return CE->getType()->castTo<FunctionType>()->isNoEscape();
138138
}
139139

140+
bool isObjC() const {
141+
if (auto afd = TheFunction.dyn_cast<AbstractFunctionDecl *>()) {
142+
return afd->isObjC();
143+
}
144+
if (TheFunction.dyn_cast<AbstractClosureExpr *>()) {
145+
// Closures are never @objc.
146+
return false;
147+
}
148+
llvm_unreachable("unexpected AnyFunctionRef representation");
149+
}
150+
151+
SourceLoc getLoc() const {
152+
if (auto afd = TheFunction.dyn_cast<AbstractFunctionDecl *>()) {
153+
return afd->getLoc();
154+
}
155+
if (auto ce = TheFunction.dyn_cast<AbstractClosureExpr *>()) {
156+
return ce->getLoc();
157+
}
158+
llvm_unreachable("unexpected AnyFunctionRef representation");
159+
}
140160
};
141161

142162
} // namespace swift

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,8 +1061,10 @@ ERROR(extension_protocol_via_typealias,none,
10611061
ERROR(extension_anyobject,none,
10621062
"'AnyObject' protocol cannot be extended", ())
10631063
ERROR(objc_generic_extension_using_type_parameter,none,
1064-
"Extension of a generic Objective-C class cannot access the class's "
1065-
"generic parameters", ())
1064+
"extension of a generic Objective-C class cannot access the class's "
1065+
"generic parameters at runtime", ())
1066+
NOTE(objc_generic_extension_using_type_parameter_here,none,
1067+
"generic parameter used here", ())
10661068

10671069
// Protocols
10681070
ERROR(type_does_not_conform,none,

lib/AST/Type.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1919,13 +1919,14 @@ bool TypeBase::isPotentiallyBridgedValueType() {
19191919
}
19201920

19211921
/// Determine whether this is a representable Objective-C object type.
1922-
static ForeignRepresentableKind getObjCObjectRepresentable(Type type) {
1922+
static ForeignRepresentableKind getObjCObjectRepresentable(Type type,
1923+
DeclContext *dc) {
19231924
// @objc metatypes are representable when their instance type is.
19241925
if (auto metatype = type->getAs<AnyMetatypeType>()) {
19251926
// If the instance type is not representable, the metatype is not
19261927
// representable.
19271928
auto instanceType = metatype->getInstanceType();
1928-
if (getObjCObjectRepresentable(instanceType)
1929+
if (getObjCObjectRepresentable(instanceType, dc)
19291930
== ForeignRepresentableKind::None)
19301931
return ForeignRepresentableKind::None;
19311932

@@ -1955,6 +1956,14 @@ static ForeignRepresentableKind getObjCObjectRepresentable(Type type) {
19551956
// Objective-C existential types.
19561957
if (type->isObjCExistentialType())
19571958
return ForeignRepresentableKind::Object;
1959+
1960+
// Class-constrained generic parameters, from ObjC generic classes.
1961+
if (auto tyContext = dc->getInnermostTypeContext())
1962+
if (auto clas = tyContext->getAsClassOrClassExtensionContext())
1963+
if (clas->hasClangNode())
1964+
if (auto archetype = type->getAs<ArchetypeType>())
1965+
if (archetype->requiresClass())
1966+
return ForeignRepresentableKind::Object;
19581967

19591968
return ForeignRepresentableKind::None;
19601969
}
@@ -1976,7 +1985,7 @@ getForeignRepresentable(Type type, ForeignLanguage language, DeclContext *dc) {
19761985

19771986
// Objective-C object types, including metatypes.
19781987
if (language == ForeignLanguage::ObjectiveC) {
1979-
auto representable = getObjCObjectRepresentable(type);
1988+
auto representable = getObjCObjectRepresentable(type, dc);
19801989
if (representable != ForeignRepresentableKind::None)
19811990
return { representable, nullptr };
19821991
}
@@ -2137,7 +2146,7 @@ getForeignRepresentable(Type type, ForeignLanguage language, DeclContext *dc) {
21372146
pointerElt = objectType;
21382147

21392148
if (language == ForeignLanguage::ObjectiveC &&
2140-
getObjCObjectRepresentable(pointerElt)
2149+
getObjCObjectRepresentable(pointerElt, dc)
21412150
!= ForeignRepresentableKind::None)
21422151
return { ForeignRepresentableKind::Trivial, nullptr };
21432152

lib/Sema/TypeCheckExpr.cpp

Lines changed: 168 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -732,14 +732,14 @@ namespace {
732732
llvm::SmallPtrSet<ValueDecl *, 2> Diagnosed;
733733
/// The AbstractClosureExpr or AbstractFunctionDecl being analyzed.
734734
AnyFunctionRef AFR;
735-
bool &capturesTypes;
735+
SourceLoc &TypeCapturingLoc;
736736
public:
737737
FindCapturedVars(TypeChecker &tc,
738738
SmallVectorImpl<CapturedValue> &captureList,
739-
bool &capturesTypes,
739+
SourceLoc &typeCapturingLoc,
740740
AnyFunctionRef AFR)
741741
: TC(tc), captureList(captureList), AFR(AFR),
742-
capturesTypes(capturesTypes) {
742+
TypeCapturingLoc(typeCapturingLoc) {
743743
if (auto AFD = AFR.getAbstractFunctionDecl())
744744
CaptureLoc = AFD->getLoc();
745745
else {
@@ -758,22 +758,25 @@ namespace {
758758
/// FIXME: SILGen doesn't currently allow local generic functions to
759759
/// capture generic parameters from an outer context. Once it does, we
760760
/// will need to distinguish outer and inner type parameters here.
761-
void checkType(Type type) {
761+
void checkType(Type type, SourceLoc loc) {
762762
// Nothing to do if the type is concrete.
763763
if (!type || !type->hasArchetype())
764764
return;
765765

766766
// Walk the type to see if we have any archetypes that are *not* open
767767
// existentials and that aren't type-erased.
768768
class CapturesTypeWalker final : public TypeWalker {
769-
bool &CapturesTypes;
769+
SourceLoc &TypeCapturingLoc;
770+
SourceLoc CurLoc;
770771

771772
public:
772-
CapturesTypeWalker(bool &capturesTypes) : CapturesTypes(capturesTypes){}
773+
CapturesTypeWalker(SourceLoc &capturingLoc, SourceLoc curLoc)
774+
: TypeCapturingLoc(capturingLoc), CurLoc(curLoc) {}
773775

774776
Action walkToTypePre(Type t) override {
775777
if (t->is<ArchetypeType>() && !t->isOpenedExistential()) {
776-
CapturesTypes = true;
778+
if (TypeCapturingLoc.isInvalid())
779+
TypeCapturingLoc = CurLoc;
777780
return Action::Stop;
778781
}
779782

@@ -789,7 +792,7 @@ namespace {
789792
}
790793
};
791794

792-
type.walk(CapturesTypeWalker(capturesTypes));
795+
type.walk(CapturesTypeWalker(TypeCapturingLoc, loc));
793796
}
794797

795798
/// Add the specified capture to the closure's capture list, diagnosing it
@@ -812,12 +815,12 @@ namespace {
812815
captureList[entryNumber-1] = capture;
813816
}
814817

815-
// Visit the type of the capture. If we capture 'self' via a 'super' call,
816-
// and the superclass is not generic, there might not be any generic
817-
// parameter types in the closure body, so we have to account for them
818-
// here.
819-
if (VD->hasType())
820-
checkType(VD->getType());
818+
// Visit the type of the capture, if it isn't a class reference, since
819+
// we'd need the metadata to do so.
820+
if (VD->hasType()
821+
&& (!AFR.isObjC()
822+
|| !VD->getType()->hasRetainablePointerRepresentation()))
823+
checkType(VD->getType(), VD->getLoc());
821824

822825
// If VD is a noescape decl, then the closure we're computing this for
823826
// must also be noescape.
@@ -999,7 +1002,7 @@ namespace {
9991002
}
10001003

10011004
if (innerClosure.getCaptureInfo().hasGenericParamCaptures())
1002-
capturesTypes = true;
1005+
TypeCapturingLoc = innerClosure.getLoc();
10031006
}
10041007

10051008
bool walkToDeclPre(Decl *D) override {
@@ -1018,12 +1021,131 @@ namespace {
10181021

10191022
return true;
10201023
}
1024+
1025+
bool usesTypeMetadataOfFormalType(Expr *E) {
1026+
// For non-ObjC closures, assume the type metadata is always used.
1027+
if (!AFR.isObjC())
1028+
return true;
1029+
1030+
if (!E->getType() || E->getType()->is<ErrorType>())
1031+
return false;
1032+
1033+
// We can use Objective-C generics in limited ways without reifying
1034+
// their type metadata, meaning we don't need to capture their generic
1035+
// params.
1036+
1037+
// Look through one layer of optionality when considering the class-
1038+
1039+
// Referring to a class-constrained generic or metatype
1040+
// doesn't require its type metadata.
1041+
if (auto declRef = dyn_cast<DeclRefExpr>(E))
1042+
return !declRef->getDecl()->isObjC()
1043+
&& !E->getType()->hasRetainablePointerRepresentation()
1044+
&& !E->getType()->is<AnyMetatypeType>();
1045+
1046+
// Loading classes or metatypes doesn't require their metadata.
1047+
if (isa<LoadExpr>(E))
1048+
return !E->getType()->hasRetainablePointerRepresentation()
1049+
&& !E->getType()->is<AnyMetatypeType>();
1050+
1051+
// Accessing @objc members doesn't require type metadata.
1052+
if (auto memberRef = dyn_cast<MemberRefExpr>(E))
1053+
return !memberRef->getMember().getDecl()->hasClangNode();
1054+
1055+
if (auto applyExpr = dyn_cast<ApplyExpr>(E)) {
1056+
if (auto methodApply = dyn_cast<ApplyExpr>(applyExpr->getFn())) {
1057+
if (auto callee = dyn_cast<DeclRefExpr>(methodApply->getFn())) {
1058+
return !callee->getDecl()->isObjC();
1059+
}
1060+
}
1061+
if (auto callee = dyn_cast<DeclRefExpr>(applyExpr->getFn())) {
1062+
return !callee->getDecl()->isObjC();
1063+
}
1064+
}
1065+
1066+
if (auto subscriptExpr = dyn_cast<SubscriptExpr>(E)) {
1067+
return !subscriptExpr->getDecl().getDecl()->isObjC();
1068+
}
1069+
1070+
// Getting the dynamic type of a class doesn't require type metadata.
1071+
if (isa<DynamicTypeExpr>(E))
1072+
return !E->getType()->castTo<AnyMetatypeType>()->getInstanceType()
1073+
->hasRetainablePointerRepresentation();
1074+
1075+
// Building a fixed-size tuple doesn't require type metadata.
1076+
// Approximate this for the purposes of being able to invoke @objc methods
1077+
// by considering tuples of ObjC-representable types to not use metadata.
1078+
if (auto tuple = dyn_cast<TupleExpr>(E)) {
1079+
for (auto elt : tuple->getType()->castTo<TupleType>()->getElements()) {
1080+
if (!elt.getType()->isRepresentableIn(ForeignLanguage::ObjectiveC,
1081+
AFR.getAsDeclContext()))
1082+
return true;
1083+
}
1084+
return false;
1085+
}
1086+
1087+
// Coercion by itself is a no-op.
1088+
if (isa<CoerceExpr>(E))
1089+
return false;
1090+
1091+
// Upcasting doesn't require type metadata.
1092+
if (isa<DerivedToBaseExpr>(E))
1093+
return false;
1094+
if (isa<ArchetypeToSuperExpr>(E))
1095+
return false;
1096+
if (isa<CovariantReturnConversionExpr>(E))
1097+
return false;
1098+
if (isa<MetatypeConversionExpr>(E))
1099+
return false;
1100+
1101+
// Identity expressions are no-ops.
1102+
if (isa<IdentityExpr>(E))
1103+
return false;
1104+
1105+
// Discarding an assignment is a no-op.
1106+
if (isa<DiscardAssignmentExpr>(E))
1107+
return false;
1108+
1109+
// Opening an @objc existential or metatype is a no-op.
1110+
if (auto open = dyn_cast<OpenExistentialExpr>(E))
1111+
return !open->getSubExpr()->getType()->isObjCExistentialType()
1112+
&& !open->getSubExpr()->getType()->is<AnyMetatypeType>();
1113+
1114+
// Erasure to an ObjC existential or between metatypes doesn't require
1115+
// type metadata.
1116+
if (auto erasure = dyn_cast<ErasureExpr>(E)) {
1117+
if (E->getType()->isObjCExistentialType()
1118+
|| E->getType()->is<AnyMetatypeType>())
1119+
return false;
1120+
// Erasure to a Swift protocol always captures the type metadata from
1121+
// its subexpression.
1122+
checkType(erasure->getSubExpr()->getType(),
1123+
erasure->getSubExpr()->getLoc());
1124+
return true;
1125+
}
1126+
1127+
// Converting an @objc metatype to AnyObject doesn't require type
1128+
// metadata.
1129+
if (isa<ClassMetatypeToObjectExpr>(E)
1130+
|| isa<ExistentialMetatypeToObjectExpr>(E))
1131+
return false;
1132+
1133+
return true;
1134+
}
10211135

10221136
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
1023-
checkType(E->getType());
1137+
if (usesTypeMetadataOfFormalType(E)) {
1138+
checkType(E->getType(), E->getLoc());
1139+
}
1140+
1141+
// Some kinds of expression don't really evaluate their subexpression,
1142+
// so we don't need to traverse.
1143+
if (isa<ObjCSelectorExpr>(E)) {
1144+
return { false, E };
1145+
}
10241146

10251147
if (auto *ECE = dyn_cast<ExplicitCastExpr>(E)) {
1026-
checkType(ECE->getCastTypeLoc().getType());
1148+
checkType(ECE->getCastTypeLoc().getType(), ECE->getLoc());
10271149
return { true, E };
10281150
}
10291151

@@ -1038,7 +1160,7 @@ namespace {
10381160
return { false, superE };
10391161
}
10401162

1041-
// Don't recurse into child closures. They should already have a capture
1163+
// Don't recur into child closures. They should already have a capture
10421164
// list computed; we just propagate it, filtering out stuff that they
10431165
// capture from us.
10441166
if (auto *SubCE = dyn_cast<AbstractClosureExpr>(E)) {
@@ -1074,12 +1196,29 @@ void TypeChecker::computeCaptures(AnyFunctionRef AFR) {
10741196
return;
10751197

10761198
SmallVector<CapturedValue, 4> Captures;
1077-
bool GenericParamCaptures = false;
1078-
FindCapturedVars finder(*this, Captures, GenericParamCaptures, AFR);
1199+
SourceLoc GenericParamCaptureLoc;
1200+
FindCapturedVars finder(*this, Captures, GenericParamCaptureLoc, AFR);
10791201
AFR.getBody()->walk(finder);
10801202

1081-
if (AFR.hasType())
1082-
finder.checkType(AFR.getType());
1203+
if (AFR.hasType() && !AFR.isObjC()) {
1204+
finder.checkType(AFR.getType(), AFR.getLoc());
1205+
/*
1206+
for (auto paramList : AFR.getParameterLists()) {
1207+
for (auto param : *paramList) {
1208+
// Passing parameters of class type doesn't require their metadata.
1209+
if (param->hasType()
1210+
&& !param->getType()->is<MetatypeType>()
1211+
&& !param->getType()->hasRetainablePointerRepresentation())
1212+
finder.checkType(param->getType(), param->getLoc());
1213+
}
1214+
}
1215+
1216+
if (AFR.getBodyResultType()
1217+
&& !AFR.getBodyResultType()->is<MetatypeType>()
1218+
&& !AFR.getBodyResultType()->hasRetainablePointerRepresentation())
1219+
finder.checkType(AFR.getBodyResultType(), AFR.getLoc());
1220+
*/
1221+
}
10831222

10841223
// If this is an init(), explicitly walk the initializer values for members of
10851224
// the type. They will be implicitly emitted by SILGen into the generated
@@ -1111,7 +1250,8 @@ void TypeChecker::computeCaptures(AnyFunctionRef AFR) {
11111250
if (!AFD ||
11121251
(!AFD->getGenericParams() &&
11131252
AFD->getDeclContext()->isLocalContext())) {
1114-
AFR.getCaptureInfo().setGenericParamCaptures(GenericParamCaptures);
1253+
AFR.getCaptureInfo()
1254+
.setGenericParamCaptures(GenericParamCaptureLoc.isValid());
11151255
}
11161256

11171257
if (Captures.empty())
@@ -1121,11 +1261,14 @@ void TypeChecker::computeCaptures(AnyFunctionRef AFR) {
11211261

11221262
// Extensions of generic ObjC functions can't use generic parameters from
11231263
// their context.
1124-
if (AFD && GenericParamCaptures) {
1264+
if (AFD && GenericParamCaptureLoc.isValid()) {
11251265
if (auto Clas = AFD->getParent()->getAsClassOrClassExtensionContext()) {
1126-
if (Clas->isGenericContext() && Clas->hasClangNode())
1266+
if (Clas->isGenericContext() && Clas->hasClangNode()) {
11271267
diagnose(AFD->getLoc(),
11281268
diag::objc_generic_extension_using_type_parameter);
1269+
diagnose(GenericParamCaptureLoc,
1270+
diag::objc_generic_extension_using_type_parameter_here);
1271+
}
11291272
}
11301273
}
11311274

0 commit comments

Comments
 (0)