Skip to content

Commit 038761f

Browse files
committed
[TypeChecker] NFC: Add a unittest for closure inference with optional contextual type
1 parent 0562c31 commit 038761f

File tree

1 file changed

+82
-0
lines changed

1 file changed

+82
-0
lines changed

unittests/Sema/ConstraintSimplificationTests.cpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "SemaFixture.h"
14+
#include "swift/AST/Decl.h"
15+
#include "swift/AST/Expr.h"
16+
#include "swift/AST/ParameterList.h"
17+
#include "swift/AST/Types.h"
1418
#include "swift/Sema/ConstraintSystem.h"
1519

1620
using namespace swift;
@@ -44,3 +48,81 @@ TEST_F(SemaTest, TestTrailingClosureMatchRecordingForIdenticalFunctions) {
4448
TrailingClosureMatching::Forward, {{0}, {1}}, None};
4549
ASSERT_EQ(choice->second, expected);
4650
}
51+
52+
/// Emulates code like this:
53+
///
54+
/// func test(_: ((Int) -> Void)?) {}
55+
///
56+
/// test { $0 }
57+
///
58+
/// To make sure that closure resolution propagates contextual
59+
/// information into the body of the closure even when contextual
60+
/// type is wrapped in an optional.
61+
TEST_F(SemaTest, TestClosureInferenceFromOptionalContext) {
62+
ConstraintSystem cs(DC, ConstraintSystemOptions());
63+
64+
DeclAttributes closureAttrs;
65+
66+
// Anonymous closure parameter
67+
auto paramName = Context.getIdentifier("0");
68+
69+
auto *paramDecl =
70+
new (Context) ParamDecl(/*specifierLoc=*/SourceLoc(),
71+
/*argumentNameLoc=*/SourceLoc(), paramName,
72+
/*parameterNameLoc=*/SourceLoc(), paramName, DC);
73+
74+
paramDecl->setSpecifier(ParamSpecifier::Default);
75+
76+
auto *closure = new (Context) ClosureExpr(
77+
closureAttrs,
78+
/*bracketRange=*/SourceRange(),
79+
/*capturedSelfDecl=*/nullptr, ParameterList::create(Context, {paramDecl}),
80+
/*asyncLoc=*/SourceLoc(),
81+
/*throwsLoc=*/SourceLoc(),
82+
/*arrowLoc=*/SourceLoc(),
83+
/*inLoc=*/SourceLoc(),
84+
/*explicitResultType=*/nullptr,
85+
/*discriminator=*/0,
86+
/*parent=*/DC);
87+
88+
closure->setImplicit();
89+
90+
closure->setBody(BraceStmt::create(Context, /*startLoc=*/SourceLoc(), {},
91+
/*endLoc=*/SourceLoc()),
92+
/*isSingleExpression=*/false);
93+
94+
auto *closureLoc = cs.getConstraintLocator(closure);
95+
96+
auto *paramTy = cs.createTypeVariable(
97+
cs.getConstraintLocator(closure, LocatorPathElt::TupleElement(0)),
98+
/*options=*/TVO_CanBindToInOut);
99+
100+
auto *resultTy = cs.createTypeVariable(
101+
cs.getConstraintLocator(closure, ConstraintLocator::ClosureResult),
102+
/*options=*/0);
103+
104+
auto extInfo = FunctionType::ExtInfo();
105+
106+
auto defaultTy = FunctionType::get({FunctionType::Param(paramTy, paramName)},
107+
resultTy, extInfo);
108+
109+
cs.setClosureType(closure, defaultTy);
110+
111+
auto *closureTy = cs.createTypeVariable(closureLoc, /*options=*/0);
112+
113+
cs.addUnsolvedConstraint(Constraint::create(
114+
cs, ConstraintKind::DefaultClosureType, closureTy, defaultTy,
115+
cs.getConstraintLocator(closure), /*referencedVars=*/{}));
116+
117+
auto contextualTy =
118+
FunctionType::get({FunctionType::Param(getStdlibType("Int"))},
119+
Context.TheEmptyTupleType, extInfo);
120+
121+
// Try to resolve closure:
122+
// - external type `paramTy` should get bound to `Int`.
123+
// - result type should be bound to `Void`.
124+
cs.resolveClosure(closureTy, OptionalType::get(contextualTy), closureLoc);
125+
126+
ASSERT_TRUE(cs.simplifyType(paramTy)->isEqual(getStdlibType("Int")));
127+
ASSERT_TRUE(cs.simplifyType(resultTy)->isEqual(Context.TheEmptyTupleType));
128+
}

0 commit comments

Comments
 (0)