Skip to content

Commit dec5f54

Browse files
committed
SILGen: Properly lower types of ObjC generic methods dispatched off AnyObject.
When an ObjC generic method is found by AnyObject dispatch, we don't have any type information to bind generic parameter dependencies. Sema expands these generic parameters to their upper bounds in an AnyObject dispatch. However, SILGen was still lowering the type of a dynamic method invocation from the method's formal type, expecting its generic parameters to be bound by substitutions provided from a call. Lower dynamic method calls using the substituted type from the AST instead to avoid this. Fixes rdar://problem/26380562.
1 parent 1a0891c commit dec5f54

File tree

7 files changed

+120
-29
lines changed

7 files changed

+120
-29
lines changed

include/swift/AST/Types.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,10 @@ class alignas(1 << TypeAlignInBits) TypeBase {
656656
/// of \c ty.
657657
bool isBindableToSuperclassOf(Type ty, LazyResolver *resolver);
658658

659+
/// True if this type contains archetypes that could be substituted with
660+
/// concrete types to form the argument type.
661+
bool isBindableTo(Type ty, LazyResolver *resolver);
662+
659663
/// \brief Determines whether this type is permitted as a method override
660664
/// of the \p other.
661665
bool canOverride(Type other, OverrideMatchMode matchMode,

include/swift/SIL/TypeLowering.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,13 @@ class TypeConverter {
810810
ABIDifference checkFunctionForABIDifferences(SILFunctionType *fnTy1,
811811
SILFunctionType *fnTy2);
812812

813+
814+
/// Lower the function type as a possible substitution for the type of
815+
/// \p constant. The result is not cached as part of the constant's normal
816+
/// ConstantInfo.
817+
CanSILFunctionType
818+
getUncachedSILFunctionTypeForConstant(SILDeclRef constant,
819+
CanAnyFunctionType origInterfaceType);
813820
private:
814821
Type getLoweredCBridgedType(AbstractionPattern pattern, Type t,
815822
bool canBridgeBool,

lib/AST/Type.cpp

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1639,7 +1639,7 @@ bool TypeBase::isExactSuperclassOf(Type ty, LazyResolver *resolver) {
16391639
}
16401640

16411641
/// Returns true if type `a` has archetypes that can be bound to form `b`.
1642-
static bool isBindableTo(Type a, Type b, LazyResolver *resolver) {
1642+
bool TypeBase::isBindableTo(Type b, LazyResolver *resolver) {
16431643
class IsBindableVisitor : public TypeVisitor<IsBindableVisitor, bool, CanType>
16441644
{
16451645
llvm::DenseMap<ArchetypeType *, CanType> Bindings;
@@ -1655,11 +1655,24 @@ static bool isBindableTo(Type a, Type b, LazyResolver *resolver) {
16551655
if (bound != Bindings.end()) {
16561656
return bound->second->isEqual(subst);
16571657
}
1658+
1659+
auto canBindClassConstrainedArchetype = [](CanType t) -> bool {
1660+
// Classes and class-constrained archetypes.
1661+
if (t->mayHaveSuperclass())
1662+
return true;
1663+
1664+
// Pure @objc existentials.
1665+
if (t->isObjCExistentialType())
1666+
return true;
1667+
1668+
return false;
1669+
};
1670+
16581671
// Check that the archetype isn't constrained in a way that makes the
16591672
// binding impossible.
16601673
// For instance, if the archetype is class-constrained, and the binding
16611674
// is not a class, it can never be bound.
1662-
if (orig->requiresClass() && !subst->mayHaveSuperclass())
1675+
if (orig->requiresClass() && !canBindClassConstrainedArchetype(subst))
16631676
return false;
16641677

16651678
// TODO: If the archetype has a superclass constraint, check that the
@@ -1750,6 +1763,46 @@ static bool isBindableTo(Type a, Type b, LazyResolver *resolver) {
17501763
return false;
17511764
}
17521765

1766+
bool visitSILFunctionType(SILFunctionType *func,
1767+
CanType subst) {
1768+
if (auto substFunc = dyn_cast<SILFunctionType>(subst)) {
1769+
if (func->getExtInfo() != substFunc->getExtInfo())
1770+
return false;
1771+
1772+
// TODO: Generic signatures
1773+
if (func->getGenericSignature() || substFunc->getGenericSignature())
1774+
return false;
1775+
1776+
if (func->getParameters().size() != substFunc->getParameters().size())
1777+
return false;
1778+
if (func->getAllResults().size() != substFunc->getAllResults().size())
1779+
return false;
1780+
1781+
for (unsigned i : indices(func->getParameters())) {
1782+
if (func->getParameters()[i].getConvention()
1783+
!= substFunc->getParameters()[i].getConvention())
1784+
return false;
1785+
if (!visit(func->getParameters()[i].getType(),
1786+
substFunc->getParameters()[i].getType()))
1787+
return false;
1788+
}
1789+
1790+
for (unsigned i : indices(func->getAllResults())) {
1791+
if (func->getAllResults()[i].getConvention()
1792+
!= substFunc->getAllResults()[i].getConvention())
1793+
return false;
1794+
1795+
if (!visit(func->getAllResults()[i].getType(),
1796+
substFunc->getAllResults()[i].getType()))
1797+
return false;
1798+
}
1799+
1800+
return true;
1801+
}
1802+
1803+
return false;
1804+
}
1805+
17531806
bool visitBoundGenericType(BoundGenericType *bgt, CanType subst) {
17541807
if (auto substBGT = dyn_cast<BoundGenericType>(subst)) {
17551808
if (bgt->getDecl() != substBGT->getDecl())
@@ -1798,7 +1851,7 @@ static bool isBindableTo(Type a, Type b, LazyResolver *resolver) {
17981851
}
17991852
};
18001853

1801-
return IsBindableVisitor(resolver).visit(a->getCanonicalType(),
1854+
return IsBindableVisitor(resolver).visit(getCanonicalType(),
18021855
b->getCanonicalType());
18031856
}
18041857

@@ -1822,7 +1875,7 @@ bool TypeBase::isBindableToSuperclassOf(Type ty, LazyResolver *resolver) {
18221875
return true;
18231876

18241877
do {
1825-
if (isBindableTo(this, ty, resolver))
1878+
if (isBindableTo(ty, resolver))
18261879
return true;
18271880
if (ty->getAnyNominal() && ty->getAnyNominal()->isInvalid())
18281881
return false;

lib/SIL/SILFunctionType.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1495,7 +1495,8 @@ getSILFunctionTypeForSelectorFamily(SILModule &M, SelectorFamily family,
14951495
}
14961496

14971497
static CanSILFunctionType
1498-
getUncachedSILFunctionTypeForConstant(SILModule &M, SILDeclRef constant,
1498+
getUncachedSILFunctionTypeForConstant(SILModule &M,
1499+
SILDeclRef constant,
14991500
CanAnyFunctionType origLoweredInterfaceType) {
15001501
assert(origLoweredInterfaceType->getExtInfo().getSILRepresentation()
15011502
!= SILFunctionTypeRepresentation::Thick
@@ -1505,7 +1506,7 @@ getUncachedSILFunctionTypeForConstant(SILModule &M, SILDeclRef constant,
15051506
auto extInfo = origLoweredInterfaceType->getExtInfo();
15061507

15071508
if (!constant.isForeign) {
1508-
return getNativeSILFunctionType(M,
1509+
return ::getNativeSILFunctionType(M,
15091510
AbstractionPattern(origLoweredInterfaceType),
15101511
origLoweredInterfaceType,
15111512
extInfo,
@@ -1538,6 +1539,16 @@ getUncachedSILFunctionTypeForConstant(SILModule &M, SILDeclRef constant,
15381539
extInfo, foreignError);
15391540
}
15401541

1542+
CanSILFunctionType TypeConverter::
1543+
getUncachedSILFunctionTypeForConstant(SILDeclRef constant,
1544+
CanAnyFunctionType origInterfaceType) {
1545+
auto origLoweredInterfaceType = getLoweredASTFunctionType(origInterfaceType,
1546+
constant.uncurryLevel,
1547+
constant);
1548+
return ::getUncachedSILFunctionTypeForConstant(M, constant,
1549+
origLoweredInterfaceType);
1550+
}
1551+
15411552
static bool isClassOrProtocolMethod(ValueDecl *vd) {
15421553
if (!vd->getDeclContext())
15431554
return false;
@@ -1620,8 +1631,8 @@ SILConstantInfo TypeConverter::getConstantInfo(SILDeclRef constant) {
16201631

16211632
// The SIL type encodes conventions according to the original type.
16221633
CanSILFunctionType silFnType =
1623-
getUncachedSILFunctionTypeForConstant(M, constant,
1624-
loweredInterfaceType);
1634+
::getUncachedSILFunctionTypeForConstant(M, constant,
1635+
loweredInterfaceType);
16251636

16261637
DEBUG(llvm::dbgs() << "lowering type for constant ";
16271638
constant.print(llvm::dbgs());

lib/SIL/SILVerifier.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "swift/SIL/SILVTable.h"
1919
#include "swift/SIL/Dominance.h"
2020
#include "swift/SIL/DynamicCasts.h"
21+
#include "swift/AST/AnyFunctionRef.h"
2122
#include "swift/AST/ASTContext.h"
2223
#include "swift/AST/Decl.h"
2324
#include "swift/AST/Module.h"
@@ -1708,7 +1709,10 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
17081709
dynResults,
17091710
methodTy->getOptionalErrorResult(),
17101711
F.getASTContext());
1711-
return SILType::getPrimitiveObjectType(fnTy);
1712+
auto boundFnTy = ArchetypeBuilder::mapTypeIntoContext(
1713+
method.getDecl()->getDeclContext(), fnTy)
1714+
->getCanonicalType();
1715+
return SILType::getPrimitiveObjectType(boundFnTy);
17121716
}
17131717

17141718
void checkDynamicMethodInst(DynamicMethodInst *EMI) {
@@ -1721,12 +1725,13 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
17211725
"operand must have metatype type");
17221726
require(operandType.getSwiftType()->castTo<MetatypeType>()
17231727
->getInstanceType()->mayHaveSuperclass(),
1724-
"operand must have metatype of class or class-bound type");
1728+
"operand must have metatype of class or class-bounded type");
17251729
}
17261730

1727-
requireSameType(EMI->getType(),
1728-
getDynamicMethodType(operandType, EMI->getMember()),
1729-
"result must be of the method's type");
1731+
require(getDynamicMethodType(operandType, EMI->getMember())
1732+
.getSwiftRValueType()
1733+
->isBindableTo(EMI->getType().getSwiftRValueType(), nullptr),
1734+
"result must be of the method's type");
17301735
}
17311736

17321737
void checkClassMethodInst(ClassMethodInst *CMI) {

lib/SILGen/SILGenApply.cpp

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -281,17 +281,17 @@ class Callee {
281281

282282
/// Add the 'self' type to the substituted function type of this
283283
/// dynamic callee.
284-
void addDynamicCalleeSelfToFormalType(SILGenModule &SGM) {
284+
void addDynamicCalleeSelfToFormalType(SILGenModule &SGM,
285+
CanAnyFunctionType substFormalType) {
285286
assert(kind == Kind::DynamicMethod);
286287

287-
// Drop the original self clause.
288-
CanType methodType = OrigFormalInterfaceType.getResult();
289-
290-
// Replace it with the dynamic self type.
288+
// Add the dynamic self type to the substituted type. Even if the dynamic
289+
// callee came from a generic ObjC class, when we find it on AnyObject the
290+
// parameters should be substituted with their upper bound types.
291291
OrigFormalInterfaceType
292292
= getDynamicMethodFormalType(SGM, SelfValue,
293293
Constant.getDecl(),
294-
Constant, methodType);
294+
Constant, substFormalType);
295295
assert(!OrigFormalInterfaceType->hasTypeParameter());
296296

297297
// Add a self clause to the substituted type.
@@ -354,7 +354,7 @@ class Callee {
354354
SILLocation l) {
355355
Callee callee(Kind::DynamicMethod, gen, proto, name,
356356
substFormalType, l);
357-
callee.addDynamicCalleeSelfToFormalType(gen.SGM);
357+
callee.addDynamicCalleeSelfToFormalType(gen.SGM, substFormalType);
358358
return callee;
359359
}
360360
Callee(Callee &&) = default;
@@ -425,7 +425,6 @@ class Callee {
425425
getAtUncurryLevel(SILGenFunction &gen, unsigned level) const {
426426
ManagedValue mv;
427427
ApplyOptions options = ApplyOptions::None;
428-
SILConstantInfo constantInfo;
429428
Optional<SILDeclRef> constant = None;
430429

431430
switch (kind) {
@@ -447,7 +446,7 @@ class Callee {
447446
if (getMethodDispatch(func) == MethodDispatch::Class)
448447
constant = constant->asDirectReference(true);
449448

450-
constantInfo = gen.getConstantInfo(*constant);
449+
auto constantInfo = gen.getConstantInfo(*constant);
451450
SILValue ref = gen.emitGlobalFunctionRef(Loc, *constant, constantInfo);
452451
mv = ManagedValue::forUnmanaged(ref);
453452
break;
@@ -456,7 +455,7 @@ class Callee {
456455
assert(level <= Constant.uncurryLevel
457456
&& "uncurrying past natural uncurry level of enum constructor");
458457
constant = Constant.atUncurryLevel(level);
459-
constantInfo = gen.getConstantInfo(*constant);
458+
auto constantInfo = gen.getConstantInfo(*constant);
460459

461460
// We should not end up here if the enum constructor call is fully
462461
// applied.
@@ -470,7 +469,7 @@ class Callee {
470469
assert(level <= Constant.uncurryLevel
471470
&& "uncurrying past natural uncurry level of method");
472471
constant = Constant.atUncurryLevel(level);
473-
constantInfo = gen.getConstantInfo(*constant);
472+
auto constantInfo = gen.getConstantInfo(*constant);
474473

475474
// If the call is curried, emit a direct call to the curry thunk.
476475
if (level < Constant.uncurryLevel) {
@@ -496,7 +495,7 @@ class Callee {
496495
"Currying the self parameter of super method calls should've been emitted");
497496

498497
constant = Constant.atUncurryLevel(level);
499-
constantInfo = gen.getConstantInfo(*constant);
498+
auto constantInfo = gen.getConstantInfo(*constant);
500499

501500
if (SILDeclRef baseConstant = Constant.getBaseOverriddenVTableEntry())
502501
constantInfo = gen.SGM.Types.getConstantOverrideInfo(Constant,
@@ -514,7 +513,7 @@ class Callee {
514513
assert(level <= Constant.uncurryLevel
515514
&& "uncurrying past natural uncurry level of method");
516515
constant = Constant.atUncurryLevel(level);
517-
constantInfo = gen.getConstantInfo(*constant);
516+
auto constantInfo = gen.getConstantInfo(*constant);
518517

519518
// If the call is curried, emit a direct call to the curry thunk.
520519
if (level < Constant.uncurryLevel) {
@@ -550,11 +549,16 @@ class Callee {
550549
&& "uncurrying past natural uncurry level of method");
551550

552551
auto constant = Constant.atUncurryLevel(level);
553-
constantInfo = gen.getConstantInfo(constant);
552+
// Lower the substituted type from the AST, which should have any generic
553+
// parameters in the original signature erased to their upper bounds.
554+
auto objcFormalType = CanAnyFunctionType(SubstFormalType->withExtInfo(
555+
SubstFormalType->getExtInfo()
556+
.withSILRepresentation(SILFunctionTypeRepresentation::ObjCMethod)));
557+
auto fnType = gen.SGM.M.Types
558+
.getUncachedSILFunctionTypeForConstant(constant, objcFormalType);
554559

555560
auto closureType =
556-
replaceSelfTypeForDynamicLookup(gen.getASTContext(),
557-
constantInfo.SILFnType,
561+
replaceSelfTypeForDynamicLookup(gen.getASTContext(), fnType,
558562
SelfValue->getType().getSwiftRValueType(),
559563
Constant);
560564

test/SILGen/objc_imported_generic.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,10 @@ func callInitializer() {
99

1010
// CHECK-LABEL: sil shared @_TFCSo12GenericClassCfT5thingGSQx__GSQGS_x__
1111
// CHECK: thick_to_objc_metatype {{%.*}} : $@thick GenericClass<T>.Type to $@objc_metatype GenericClass<T>.Type
12+
13+
public func genericMethodOnAnyObject(o: AnyObject, b: Bool) -> AnyObject {
14+
return o.thing!()!
15+
}
16+
17+
// CHECK-LABEL: sil @_TF21objc_imported_generic24genericMethodOnAnyObject
18+
// CHECK: dynamic_method [volatile] {{%.*}} : $@opened([[TAG:.*]]) AnyObject, #GenericClass.thing!1.foreign : <T where T : AnyObject> GenericClass<T> -> () -> T?, $@convention(objc_method) (@opened([[TAG]]) AnyObject) -> @autoreleased Optional<AnyObject>

0 commit comments

Comments
 (0)