|
11 | 11 | //===----------------------------------------------------------------------===//
|
12 | 12 |
|
13 | 13 | #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" |
14 | 18 | #include "swift/Sema/ConstraintSystem.h"
|
15 | 19 |
|
16 | 20 | using namespace swift;
|
@@ -44,3 +48,81 @@ TEST_F(SemaTest, TestTrailingClosureMatchRecordingForIdenticalFunctions) {
|
44 | 48 | TrailingClosureMatching::Forward, {{0}, {1}}, None};
|
45 | 49 | ASSERT_EQ(choice->second, expected);
|
46 | 50 | }
|
| 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