Skip to content

Commit 369cf24

Browse files
committed
Merge pull request #2662 from jckarter/anyobject-objc-generic-method
SILGen: Properly lower types of ObjC generic methods dispatched off AnyObject.
2 parents cb5a225 + dec5f54 commit 369cf24

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
@@ -302,17 +302,17 @@ class Callee {
302302

303303
/// Add the 'self' type to the substituted function type of this
304304
/// dynamic callee.
305-
void addDynamicCalleeSelfToFormalType(SILGenModule &SGM) {
305+
void addDynamicCalleeSelfToFormalType(SILGenModule &SGM,
306+
CanAnyFunctionType substFormalType) {
306307
assert(kind == Kind::DynamicMethod);
307308

308-
// Drop the original self clause.
309-
CanType methodType = OrigFormalInterfaceType.getResult();
310-
311-
// Replace it with the dynamic self type.
309+
// Add the dynamic self type to the substituted type. Even if the dynamic
310+
// callee came from a generic ObjC class, when we find it on AnyObject the
311+
// parameters should be substituted with their upper bound types.
312312
OrigFormalInterfaceType
313313
= getDynamicMethodFormalType(SGM, SelfValue,
314314
Constant.getDecl(),
315-
Constant, methodType);
315+
Constant, substFormalType);
316316
assert(!OrigFormalInterfaceType->hasTypeParameter());
317317

318318
// Add a self clause to the substituted type.
@@ -378,7 +378,7 @@ class Callee {
378378
SILLocation l) {
379379
Callee callee(Kind::DynamicMethod, gen, proto, name,
380380
substFormalType, l);
381-
callee.addDynamicCalleeSelfToFormalType(gen.SGM);
381+
callee.addDynamicCalleeSelfToFormalType(gen.SGM, substFormalType);
382382
return callee;
383383
}
384384
Callee(Callee &&) = default;
@@ -449,7 +449,6 @@ class Callee {
449449
getAtUncurryLevel(SILGenFunction &gen, unsigned level) const {
450450
ManagedValue mv;
451451
ApplyOptions options = ApplyOptions::None;
452-
SILConstantInfo constantInfo;
453452
Optional<SILDeclRef> constant = None;
454453

455454
switch (kind) {
@@ -471,7 +470,7 @@ class Callee {
471470
if (getMethodDispatch(func) == MethodDispatch::Class)
472471
constant = constant->asDirectReference(true);
473472

474-
constantInfo = gen.getConstantInfo(*constant);
473+
auto constantInfo = gen.getConstantInfo(*constant);
475474
SILValue ref = gen.emitGlobalFunctionRef(Loc, *constant, constantInfo);
476475
mv = ManagedValue::forUnmanaged(ref);
477476
break;
@@ -480,7 +479,7 @@ class Callee {
480479
assert(level <= Constant.uncurryLevel
481480
&& "uncurrying past natural uncurry level of enum constructor");
482481
constant = Constant.atUncurryLevel(level);
483-
constantInfo = gen.getConstantInfo(*constant);
482+
auto constantInfo = gen.getConstantInfo(*constant);
484483

485484
// We should not end up here if the enum constructor call is fully
486485
// applied.
@@ -494,7 +493,7 @@ class Callee {
494493
assert(level <= Constant.uncurryLevel
495494
&& "uncurrying past natural uncurry level of method");
496495
constant = Constant.atUncurryLevel(level);
497-
constantInfo = gen.getConstantInfo(*constant);
496+
auto constantInfo = gen.getConstantInfo(*constant);
498497

499498
// If the call is curried, emit a direct call to the curry thunk.
500499
if (level < Constant.uncurryLevel) {
@@ -520,7 +519,7 @@ class Callee {
520519
"Currying the self parameter of super method calls should've been emitted");
521520

522521
constant = Constant.atUncurryLevel(level);
523-
constantInfo = gen.getConstantInfo(*constant);
522+
auto constantInfo = gen.getConstantInfo(*constant);
524523

525524
if (SILDeclRef baseConstant = Constant.getBaseOverriddenVTableEntry())
526525
constantInfo = gen.SGM.Types.getConstantOverrideInfo(Constant,
@@ -538,7 +537,7 @@ class Callee {
538537
assert(level <= Constant.uncurryLevel
539538
&& "uncurrying past natural uncurry level of method");
540539
constant = Constant.atUncurryLevel(level);
541-
constantInfo = gen.getConstantInfo(*constant);
540+
auto constantInfo = gen.getConstantInfo(*constant);
542541

543542
// If the call is curried, emit a direct call to the curry thunk.
544543
if (level < Constant.uncurryLevel) {
@@ -574,11 +573,16 @@ class Callee {
574573
&& "uncurrying past natural uncurry level of method");
575574

576575
auto constant = Constant.atUncurryLevel(level);
577-
constantInfo = gen.getConstantInfo(constant);
576+
// Lower the substituted type from the AST, which should have any generic
577+
// parameters in the original signature erased to their upper bounds.
578+
auto objcFormalType = CanAnyFunctionType(SubstFormalType->withExtInfo(
579+
SubstFormalType->getExtInfo()
580+
.withSILRepresentation(SILFunctionTypeRepresentation::ObjCMethod)));
581+
auto fnType = gen.SGM.M.Types
582+
.getUncachedSILFunctionTypeForConstant(constant, objcFormalType);
578583

579584
auto closureType =
580-
replaceSelfTypeForDynamicLookup(gen.getASTContext(),
581-
constantInfo.SILFnType,
585+
replaceSelfTypeForDynamicLookup(gen.getASTContext(), fnType,
582586
SelfValue->getType().getSwiftRValueType(),
583587
Constant);
584588

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)