Skip to content

Commit 4a67288

Browse files
authored
Merge pull request #41440 from zoecarver/members-with-dependent-types
[cxx-interop] Fix calling methods with dependent types.
2 parents 385f38b + d3950e5 commit 4a67288

File tree

5 files changed

+127
-2
lines changed

5 files changed

+127
-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
@@ -217,10 +238,27 @@ synthesizeDependentTypeThunkParamForwarding(AbstractFunctionDecl *afd, void *con
217238
paramIndex++;
218239
}
219240

220-
auto *specializedFuncDeclRef = new (ctx) DeclRefExpr(ConcreteDeclRef(specializedFuncDecl),
241+
Expr *specializedFuncDeclRef = new (ctx) DeclRefExpr(ConcreteDeclRef(specializedFuncDecl),
221242
DeclNameLoc(), true);
222243
specializedFuncDeclRef->setType(specializedFuncDecl->getInterfaceType());
223244

245+
if (specializedFuncDecl->isInstanceMember()) {
246+
auto selfExpr = createSelfExpr(thunkDecl);
247+
auto *memberCall = DotSyntaxCallExpr::create(ctx, specializedFuncDeclRef, SourceLoc(), selfExpr);
248+
memberCall->setThrows(false);
249+
auto resultType = specializedFuncDecl->getInterfaceType()->getAs<FunctionType>()->getResult();
250+
specializedFuncDeclRef = memberCall;
251+
specializedFuncDeclRef->setType(resultType);
252+
} else if (specializedFuncDecl->isStatic()) {
253+
auto resultType = specializedFuncDecl->getInterfaceType()->getAs<FunctionType>()->getResult();
254+
auto selfType = cast<NominalTypeDecl>(thunkDecl->getDeclContext()->getAsDecl())->getDeclaredInterfaceType();
255+
auto selfTypeExpr = TypeExpr::createImplicit(selfType, ctx);
256+
auto *memberCall = DotSyntaxCallExpr::create(ctx, specializedFuncDeclRef, SourceLoc(), selfTypeExpr);
257+
memberCall->setThrows(false);
258+
specializedFuncDeclRef = memberCall;
259+
specializedFuncDeclRef->setType(resultType);
260+
}
261+
224262
auto argList = ArgumentList::createImplicit(ctx, forwardingParams);
225263
auto *specializedFuncCallExpr = CallExpr::createImplicit(ctx, specializedFuncDeclRef, argList);
226264
specializedFuncCallExpr->setType(specializedFuncDecl->getResultInterfaceType());
@@ -291,6 +329,7 @@ static ValueDecl *addThunkForDependentTypes(FuncDecl *oldDecl,
291329
newFnDecl->copyFormalAccessFrom(newDecl);
292330
newFnDecl->setBodySynthesizer(synthesizeDependentTypeThunkParamForwarding, newDecl);
293331
newFnDecl->setSelfAccessKind(newDecl->getSelfAccessKind());
332+
if (newDecl->isStatic()) newFnDecl->setStatic();
294333
newFnDecl->getAttrs().add(
295334
new (newDecl->getASTContext()) TransparentAttr(/*IsImplicit=*/true));
296335
return newFnDecl;
@@ -320,10 +359,27 @@ synthesizeForwardingThunkBody(AbstractFunctionDecl *afd, void *context) {
320359
forwardingParams.push_back(Argument(SourceLoc(), Identifier(), paramRefExpr));
321360
}
322361

323-
auto *specializedFuncDeclRef = new (ctx) DeclRefExpr(ConcreteDeclRef(specializedFuncDecl),
362+
Expr *specializedFuncDeclRef = new (ctx) DeclRefExpr(ConcreteDeclRef(specializedFuncDecl),
324363
DeclNameLoc(), true);
325364
specializedFuncDeclRef->setType(specializedFuncDecl->getInterfaceType());
326365

366+
if (specializedFuncDecl->isInstanceMember()) {
367+
auto selfExpr = createSelfExpr(thunkDecl);
368+
auto *memberCall = DotSyntaxCallExpr::create(ctx, specializedFuncDeclRef, SourceLoc(), selfExpr);
369+
memberCall->setThrows(false);
370+
auto resultType = specializedFuncDecl->getInterfaceType()->getAs<FunctionType>()->getResult();
371+
specializedFuncDeclRef = memberCall;
372+
specializedFuncDeclRef->setType(resultType);
373+
} else if (specializedFuncDecl->isStatic()) {
374+
auto resultType = specializedFuncDecl->getInterfaceType()->getAs<FunctionType>()->getResult();
375+
auto selfType = cast<NominalTypeDecl>(thunkDecl->getDeclContext()->getAsDecl())->getDeclaredInterfaceType();
376+
auto selfTypeExpr = TypeExpr::createImplicit(selfType, ctx);
377+
auto *memberCall = DotSyntaxCallExpr::create(ctx, specializedFuncDeclRef, SourceLoc(), selfTypeExpr);
378+
memberCall->setThrows(false);
379+
specializedFuncDeclRef = memberCall;
380+
specializedFuncDeclRef->setType(resultType);
381+
}
382+
327383
auto argList = ArgumentList::createImplicit(ctx, forwardingParams);
328384
auto *specializedFuncCallExpr = CallExpr::createImplicit(ctx, specializedFuncDeclRef, argList);
329385
specializedFuncCallExpr->setType(thunkDecl->getResultInterfaceType());
@@ -391,6 +447,7 @@ static ValueDecl *generateThunkForExtraMetatypes(SubstitutionMap subst,
391447
thunk->copyFormalAccessFrom(newDecl);
392448
thunk->setBodySynthesizer(synthesizeForwardingThunkBody, newDecl);
393449
thunk->setSelfAccessKind(newDecl->getSelfAccessKind());
450+
if (newDecl->isStatic()) thunk->setStatic();
394451
thunk->getAttrs().add(
395452
new (newDecl->getASTContext()) TransparentAttr(/*IsImplicit=*/true));
396453

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: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,30 @@ DependentTypesTestSuite.test("Multiple dependent arguments (not inferred).") {
3535
expectEqual(m.getValue(), 42)
3636
}
3737

38+
// We still have some problems calling methods on Windows: SR-13129 and rdar://88391102
39+
#if !os(Windows)
40+
DependentTypesTestSuite.test("Function template methods") {
41+
let m = M<Int>(value: 42)
42+
let m2 = m.memberDependentReturnType(CInt(32)) as! M<CInt>
43+
let val: Int = m2.memberDependentParamType(m)
44+
45+
expectEqual(m2.getValue(), 32)
46+
expectEqual(val, 42)
47+
}
48+
49+
DependentTypesTestSuite.test("Function template methods (mutable)") {
50+
var m = M<CInt>(value: 2)
51+
let m2 = m.memberDependentReturnTypeMutable(42) as! M<Int>
52+
expectEqual(m2.getValue(), 42)
53+
}
54+
55+
DependentTypesTestSuite.test("Function template methods (static)") {
56+
let m = M<CInt>.memberDependentReturnTypeStatic(42) as! M<Int>
57+
expectEqual(m.getValue(), 42)
58+
59+
let m2 = M<Int>.memberDependentReturnTypeStatic(CInt(32)) as! M<CInt>
60+
expectEqual(m2.getValue(), 32)
61+
}
62+
#endif // Windows
63+
3864
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)