Skip to content

Commit 970aed5

Browse files
committed
Add unit test for overload selection
1 parent 14a2255 commit 970aed5

File tree

2 files changed

+129
-1
lines changed

2 files changed

+129
-1
lines changed

unittests/Sema/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ add_swift_unittest(swiftSemaTests
66
ConstraintSimplificationTests.cpp
77
UnresolvedMemberLookupTests.cpp
88
PlaceholderTypeInferenceTests.cpp
9-
SolutionFilteringTests.cpp)
9+
SolutionFilteringTests.cpp
10+
KeypathFunctionConversionTests.cpp)
1011

1112
target_link_libraries(swiftSemaTests
1213
PRIVATE
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
//===--- UnresolvedMemberLookupTests.cpp --------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "SemaFixture.h"
14+
#include "swift/AST/GenericParamList.h"
15+
#include "swift/Sema/ConstraintSystem.h"
16+
17+
using namespace swift;
18+
using namespace swift::unittest;
19+
using namespace swift::constraints;
20+
21+
/// Even in the face of a more permissive conversion that might be chosen based
22+
/// on other ranking rules (e.g., the overload required is non-generic), ensure
23+
/// that we will select the solution which requires the more narrow conversion
24+
/// (e.g., the overload *is* generic).
25+
TEST_F(SemaTest, TestKeypathFunctionConversionPrefersNarrowConversion) {
26+
auto *stringTypeDecl = getStdlibNominalTypeDecl("String");
27+
auto *boolTypeDecl = getStdlibNominalTypeDecl("Bool");
28+
auto boolType = boolTypeDecl->getDeclaredType();
29+
auto boolOptType = OptionalType::get(boolType);
30+
auto stringType = stringTypeDecl->getDeclaredType();
31+
32+
auto voidType = TupleType::get({}, Context);
33+
34+
auto *genericParam1 = new (Context) GenericTypeParamDecl(
35+
DC, Context.getIdentifier("T"), SourceLoc(), SourceLoc(), 0, 0, false);
36+
auto genericType1 =
37+
genericParam1->getDeclaredInterfaceType()->getAs<GenericTypeParamType>();
38+
39+
auto *genericParam2 = new (Context) GenericTypeParamDecl(
40+
DC, Context.getIdentifier("U"), SourceLoc(), SourceLoc(), 0, 1, false);
41+
auto genericType2 =
42+
genericParam2->getDeclaredInterfaceType()->getAs<GenericTypeParamType>();
43+
44+
auto declName = DeclName(Context, Context.getIdentifier("f"), {Identifier()});
45+
46+
// func f<T, U>(_: (T) -> U))
47+
auto innerGenericFnParam = AnyFunctionType::Param(genericType1);
48+
auto genericFnParamTy = FunctionType::get({innerGenericFnParam}, genericType2)
49+
->withExtInfo(AnyFunctionType::ExtInfo());
50+
auto *genericFnParamDecl = new (Context) ParamDecl(
51+
SourceLoc(), SourceLoc(), Identifier(), SourceLoc(), Identifier(), DC);
52+
genericFnParamDecl->setSpecifier(ParamSpecifier::Default);
53+
auto *genericFnParamList = ParameterList::create(
54+
Context, SourceLoc(), {genericFnParamDecl}, SourceLoc());
55+
llvm::SmallVector<GenericTypeParamDecl *, 2> genericParams = {genericParam1,
56+
genericParam2};
57+
auto *genericParamList =
58+
GenericParamList::create(Context, SourceLoc(), {}, SourceLoc());
59+
auto genericFnDecl = FuncDecl::create(
60+
Context, SourceLoc(), StaticSpellingKind::None, SourceLoc(), declName,
61+
SourceLoc(), /*async=*/false, SourceLoc(), /*throws=*/false, SourceLoc(),
62+
nullptr, genericParamList, genericFnParamList, nullptr, DC);
63+
auto genericFnParam = AnyFunctionType::Param(genericFnParamTy);
64+
llvm::SmallVector<GenericTypeParamType *, 2> genericTypeParams = {
65+
genericType1, genericType2};
66+
auto genericSig = GenericSignature::get(genericTypeParams, {});
67+
auto genericFnTy =
68+
GenericFunctionType::get(genericSig, {genericFnParam}, voidType)
69+
->withExtInfo(AnyFunctionType::ExtInfo());
70+
genericFnDecl->setInterfaceType(genericFnTy);
71+
72+
// func f(_: (String) -> Bool?)
73+
auto innerConcreteFnParam = AnyFunctionType::Param(stringType);
74+
auto concreteFnParamTy =
75+
FunctionType::get({innerConcreteFnParam}, boolOptType)
76+
->withExtInfo(AnyFunctionType::ExtInfo());
77+
auto *concreteFnParamDecl = new (Context) ParamDecl(
78+
SourceLoc(), SourceLoc(), Identifier(), SourceLoc(), Identifier(), DC);
79+
concreteFnParamDecl->setSpecifier(ParamSpecifier::Default);
80+
auto *concreteFnParamList = ParameterList::create(
81+
Context, SourceLoc(), {concreteFnParamDecl}, SourceLoc());
82+
auto concreteFnDecl = FuncDecl::create(
83+
Context, SourceLoc(), StaticSpellingKind::None, SourceLoc(), declName,
84+
SourceLoc(), /*async=*/false, SourceLoc(), /*throws=*/false, SourceLoc(),
85+
nullptr, nullptr, concreteFnParamList, nullptr, DC);
86+
auto concreteFnParam = AnyFunctionType::Param(concreteFnParamTy);
87+
auto concreteFnTy = FunctionType::get({concreteFnParam}, voidType)
88+
->withExtInfo(AnyFunctionType::ExtInfo());
89+
concreteFnDecl->setInterfaceType(concreteFnTy);
90+
91+
// \String.isEmpty
92+
auto *stringDRE = TypeExpr::createImplicitForDecl(
93+
DeclNameLoc(), stringTypeDecl, Context.getStdlibModule(), stringType);
94+
auto *isEmptyDE = new (Context) UnresolvedDotExpr(
95+
stringDRE, SourceLoc(), DeclNameRef(Context.getIdentifier("isEmpty")),
96+
DeclNameLoc(), false);
97+
auto *kpExpr = KeyPathExpr::createParsed(Context, SourceLoc(), isEmptyDE,
98+
nullptr, false);
99+
100+
// f(\String.isEmpty)
101+
auto kpArg = Argument(SourceLoc(), Identifier(), kpExpr);
102+
auto *argList = ArgumentList::create(Context, SourceLoc(), {kpArg},
103+
SourceLoc(), llvm::None, false);
104+
llvm::SmallVector<ValueDecl *, 2> fDecls = {genericFnDecl, concreteFnDecl};
105+
auto *fDRE = new (Context) OverloadedDeclRefExpr(
106+
fDecls, DeclNameLoc(), FunctionRefKind::SingleApply, false);
107+
auto *callExpr = CallExpr::create(Context, fDRE, argList, false);
108+
109+
Expr *target = callExpr;
110+
ConstraintSystem cs(DC, ConstraintSystemOptions());
111+
ASSERT_FALSE(cs.preCheckExpression(target, DC, false, true));
112+
auto *expr = cs.generateConstraints(callExpr, DC);
113+
ASSERT_TRUE(expr);
114+
115+
SmallVector<Solution, 2> solutions;
116+
cs.solve(solutions);
117+
118+
// We should have a solution.
119+
ASSERT_EQ(solutions.size(), 1u);
120+
121+
auto &solution = solutions[0];
122+
auto *locator = cs.getConstraintLocator(fDRE);
123+
auto choice = solution.getOverloadChoice(locator).choice;
124+
125+
// We should select the generic function since it requires 'less' conversion.
126+
ASSERT_EQ(choice.getDecl(), genericFnDecl);
127+
}

0 commit comments

Comments
 (0)