Skip to content

Commit 47064a0

Browse files
committed
[cxx-interop] Fix calling methods with dependent types.
Both instance members and static methods.
1 parent 008273b commit 47064a0

File tree

5 files changed

+124
-2
lines changed

5 files changed

+124
-2
lines changed

lib/Sema/CSApply.cpp

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,27 @@ static ValueDecl *rewriteIntegerTypes(SubstitutionMap subst, ValueDecl *oldDecl,
180180
return newDecl;
181181
}
182182

183+
static Expr *createSelfExpr(FuncDecl *fnDecl) {
184+
ASTContext &ctx = fnDecl->getASTContext();
185+
186+
auto selfDecl = fnDecl->getImplicitSelfDecl();
187+
auto selfRefExpr = new (ctx) DeclRefExpr(selfDecl, DeclNameLoc(),
188+
/*implicit*/ true);
189+
190+
if (!fnDecl->isMutating()) {
191+
selfRefExpr->setType(selfDecl->getInterfaceType());
192+
return selfRefExpr;
193+
}
194+
selfRefExpr->setType(LValueType::get(selfDecl->getInterfaceType()));
195+
196+
auto inoutSelfExpr = new (ctx) InOutExpr(
197+
SourceLoc(), selfRefExpr,
198+
fnDecl->mapTypeIntoContext(selfDecl->getValueInterfaceType()),
199+
/*isImplicit*/ true);
200+
inoutSelfExpr->setType(InOutType::get(selfDecl->getInterfaceType()));
201+
return inoutSelfExpr;
202+
}
203+
183204
// Synthesize a thunk body for the function created in
184205
// "addThunkForDependentTypes". This will just cast all params and forward them
185206
// along to the specialized function. It will also cast the result before
@@ -211,10 +232,27 @@ synthesizeDependentTypeThunkParamForwarding(AbstractFunctionDecl *afd, void *con
211232
paramIndex++;
212233
}
213234

214-
auto *specializedFuncDeclRef = new (ctx) DeclRefExpr(ConcreteDeclRef(specializedFuncDecl),
235+
Expr *specializedFuncDeclRef = new (ctx) DeclRefExpr(ConcreteDeclRef(specializedFuncDecl),
215236
DeclNameLoc(), true);
216237
specializedFuncDeclRef->setType(specializedFuncDecl->getInterfaceType());
217238

239+
if (specializedFuncDecl->isInstanceMember()) {
240+
auto selfExpr = createSelfExpr(thunkDecl);
241+
auto *memberCall = DotSyntaxCallExpr::create(ctx, specializedFuncDeclRef, SourceLoc(), selfExpr);
242+
memberCall->setThrows(false);
243+
auto resultType = specializedFuncDecl->getInterfaceType()->getAs<FunctionType>()->getResult();
244+
specializedFuncDeclRef = memberCall;
245+
specializedFuncDeclRef->setType(resultType);
246+
} else if (specializedFuncDecl->isStatic()) {
247+
auto resultType = specializedFuncDecl->getInterfaceType()->getAs<FunctionType>()->getResult();
248+
auto selfType = cast<NominalTypeDecl>(thunkDecl->getDeclContext()->getAsDecl())->getDeclaredInterfaceType();
249+
auto selfTypeExpr = TypeExpr::createImplicit(selfType, ctx);
250+
auto *memberCall = DotSyntaxCallExpr::create(ctx, specializedFuncDeclRef, SourceLoc(), selfTypeExpr);
251+
memberCall->setThrows(false);
252+
specializedFuncDeclRef = memberCall;
253+
specializedFuncDeclRef->setType(resultType);
254+
}
255+
218256
auto argList = ArgumentList::createImplicit(ctx, forwardingParams);
219257
auto *specializedFuncCallExpr = CallExpr::createImplicit(ctx, specializedFuncDeclRef, argList);
220258
specializedFuncCallExpr->setType(specializedFuncDecl->getResultInterfaceType());
@@ -279,6 +317,7 @@ static ValueDecl *addThunkForDependentTypes(FuncDecl *oldDecl,
279317
newFnDecl->copyFormalAccessFrom(newDecl);
280318
newFnDecl->setBodySynthesizer(synthesizeDependentTypeThunkParamForwarding, newDecl);
281319
newFnDecl->setSelfAccessKind(newDecl->getSelfAccessKind());
320+
if (newDecl->isStatic()) newFnDecl->setStatic();
282321
newFnDecl->getAttrs().add(
283322
new (newDecl->getASTContext()) TransparentAttr(/*IsImplicit=*/true));
284323
return newFnDecl;
@@ -308,10 +347,27 @@ synthesizeForwardingThunkBody(AbstractFunctionDecl *afd, void *context) {
308347
forwardingParams.push_back(Argument(SourceLoc(), Identifier(), paramRefExpr));
309348
}
310349

311-
auto *specializedFuncDeclRef = new (ctx) DeclRefExpr(ConcreteDeclRef(specializedFuncDecl),
350+
Expr *specializedFuncDeclRef = new (ctx) DeclRefExpr(ConcreteDeclRef(specializedFuncDecl),
312351
DeclNameLoc(), true);
313352
specializedFuncDeclRef->setType(specializedFuncDecl->getInterfaceType());
314353

354+
if (specializedFuncDecl->isInstanceMember()) {
355+
auto selfExpr = createSelfExpr(thunkDecl);
356+
auto *memberCall = DotSyntaxCallExpr::create(ctx, specializedFuncDeclRef, SourceLoc(), selfExpr);
357+
memberCall->setThrows(false);
358+
auto resultType = specializedFuncDecl->getInterfaceType()->getAs<FunctionType>()->getResult();
359+
specializedFuncDeclRef = memberCall;
360+
specializedFuncDeclRef->setType(resultType);
361+
} else if (specializedFuncDecl->isStatic()) {
362+
auto resultType = specializedFuncDecl->getInterfaceType()->getAs<FunctionType>()->getResult();
363+
auto selfType = cast<NominalTypeDecl>(thunkDecl->getDeclContext()->getAsDecl())->getDeclaredInterfaceType();
364+
auto selfTypeExpr = TypeExpr::createImplicit(selfType, ctx);
365+
auto *memberCall = DotSyntaxCallExpr::create(ctx, specializedFuncDeclRef, SourceLoc(), selfTypeExpr);
366+
memberCall->setThrows(false);
367+
specializedFuncDeclRef = memberCall;
368+
specializedFuncDeclRef->setType(resultType);
369+
}
370+
315371
auto argList = ArgumentList::createImplicit(ctx, forwardingParams);
316372
auto *specializedFuncCallExpr = CallExpr::createImplicit(ctx, specializedFuncDeclRef, argList);
317373
specializedFuncCallExpr->setType(thunkDecl->getResultInterfaceType());
@@ -379,6 +435,7 @@ static ValueDecl *generateThunkForExtraMetatypes(SubstitutionMap subst,
379435
thunk->copyFormalAccessFrom(newDecl);
380436
thunk->setBodySynthesizer(synthesizeForwardingThunkBody, newDecl);
381437
thunk->setSelfAccessKind(newDecl->getSelfAccessKind());
438+
if (newDecl->isStatic()) thunk->setStatic();
382439
thunk->getAttrs().add(
383440
new (newDecl->getASTContext()) TransparentAttr(/*IsImplicit=*/true));
384441

test/Interop/Cxx/templates/Inputs/dependent-types.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,18 @@ struct M {
88
using U = T;
99

1010
T getValue() const { return value; }
11+
12+
template<class U>
13+
M<U> memberDependentReturnType(U a) const { return {a}; }
14+
15+
template<class U>
16+
M<U> memberDependentReturnTypeMutable(U a) { return {a}; }
17+
18+
template<class U>
19+
static M<U> memberDependentReturnTypeStatic(U a) { return {a}; }
20+
21+
template<class U>
22+
U memberDependentParamType(M<U> a) const { return a.value; }
1123
};
1224

1325
template<class T, class U>

test/Interop/Cxx/templates/Inputs/template-type-parameter-not-in-signature.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_TEMPLATE_TYPE_PARAMETER_NOT_IN_SIGNATURE_H
22
#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_TEMPLATE_TYPE_PARAMETER_NOT_IN_SIGNATURE_H
33

4+
struct Struct {
5+
template <typename T>
6+
void templateTypeParamNotUsedInSignature() const {}
7+
8+
template <typename T>
9+
T templateTypeParamUsedInReturnType(int x) const { return x; }
10+
11+
template <typename T>
12+
void templateTypeParamNotUsedInSignatureMutable() {}
13+
14+
template <typename T>
15+
static void templateTypeParamNotUsedInSignatureStatic() {}
16+
};
17+
418
template <typename T>
519
void templateTypeParamNotUsedInSignature() {}
620

test/Interop/Cxx/templates/dependent-types.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,27 @@ DependentTypesTestSuite.test("Multiple dependent arguments (not inferred).") {
3535
expectEqual(m.getValue(), 42)
3636
}
3737

38+
DependentTypesTestSuite.test("Function template methods") {
39+
let m = M<Int>(value: 42)
40+
let m2 = m.memberDependentReturnType(CInt(32)) as! M<CInt>
41+
let val: Int = m2.memberDependentParamType(m)
42+
43+
expectEqual(m2.getValue(), 32)
44+
expectEqual(val, 42)
45+
}
46+
47+
DependentTypesTestSuite.test("Function template methods (mutable)") {
48+
var m = M<CInt>(value: 2)
49+
let m2 = m.memberDependentReturnTypeMutable(42) as! M<Int>
50+
expectEqual(m2.getValue(), 42)
51+
}
52+
53+
DependentTypesTestSuite.test("Function template methods (static)") {
54+
let m = M<CInt>.memberDependentReturnTypeStatic(42) as! M<Int>
55+
expectEqual(m.getValue(), 42)
56+
57+
let m2 = M<Int>.memberDependentReturnTypeStatic(CInt(32)) as! M<CInt>
58+
expectEqual(m2.getValue(), 32)
59+
}
60+
3861
runAllTests()

test/Interop/Cxx/templates/template-type-parameter-not-in-signature.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,20 @@ TemplateNotInSignatureTestSuite.test("Pointer types") {
2323
expectEqual(x, 1)
2424
}
2525

26+
TemplateNotInSignatureTestSuite.test("Member function templates") {
27+
let s = Struct()
28+
s.templateTypeParamNotUsedInSignature(T: Int.self)
29+
let x: Int = templateTypeParamUsedInReturnType(42)
30+
expectEqual(x, 42)
31+
}
32+
33+
TemplateNotInSignatureTestSuite.test("Member function templates (mutable)") {
34+
var s = Struct()
35+
s.templateTypeParamNotUsedInSignatureMutable(T: Int.self)
36+
}
37+
38+
TemplateNotInSignatureTestSuite.test("Member function templates (static)") {
39+
Struct.templateTypeParamNotUsedInSignatureStatic(T: Int.self)
40+
}
41+
2642
runAllTests()

0 commit comments

Comments
 (0)