Skip to content

Commit 761b19a

Browse files
committed
---
yaml --- r: 347734 b: refs/heads/master c: f09665b h: refs/heads/master
1 parent 9cb4265 commit 761b19a

File tree

8 files changed

+125
-54
lines changed

8 files changed

+125
-54
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
refs/heads/master: ddc75d35a020090af955cee189243375a36ac21d
2+
refs/heads/master: f09665b299568dd3ceab9c5d328109ced571894d
33
refs/heads/master-next: 203b3026584ecad859eb328b2e12490099409cd5
44
refs/tags/osx-passed: b6b74147ef8a386f532cf9357a1bde006e552c54
55
refs/tags/swift-2.2-SNAPSHOT-2015-12-01-a: 6bb18e013c2284f2b45f5f84f2df2887dc0f7dea

trunk/lib/Sema/CSApply.cpp

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5678,20 +5678,27 @@ Expr *ExprRewriter::coerceCallArguments(
56785678
continue;
56795679
}
56805680

5681-
auto isAutoClosureArg = [](Expr *arg) -> bool {
5682-
if (auto *DRE = dyn_cast<DeclRefExpr>(arg)) {
5683-
if (auto *PD = dyn_cast<ParamDecl>(DRE->getDecl()))
5684-
return PD->isAutoClosure();
5681+
Expr *convertedArg = nullptr;
5682+
auto argRequiresAutoClosureExpr = [&](const AnyFunctionType::Param &param,
5683+
Type argType) {
5684+
if (!param.isAutoClosure())
5685+
return false;
5686+
5687+
// Since it was allowed to pass function types to @autoclosure
5688+
// parameters in Swift versions < 5, it has to be handled as
5689+
// a regular function coversion by `coerceToType`.
5690+
if (isAutoClosureArgument(arg)) {
5691+
// In Swift >= 5 mode we only allow `@autoclosure` arguments
5692+
// to be used by value if parameter would return a function
5693+
// type (it just needs to get wrapped into autoclosure expr),
5694+
// otherwise argument must always form a call.
5695+
return cs.getASTContext().isSwiftVersionAtLeast(5);
56855696
}
5686-
return false;
5697+
5698+
return true;
56875699
};
56885700

5689-
Expr *convertedArg = nullptr;
5690-
// Since it was allowed to pass function types to @autoclosure
5691-
// parameters in Swift versions < 5, it has to be handled as
5692-
// a regular function coversion by `coerceToType`.
5693-
if (param.isAutoClosure() && (!argType->is<FunctionType>() ||
5694-
!isAutoClosureArg(arg))) {
5701+
if (argRequiresAutoClosureExpr(param, argType)) {
56955702
assert(!param.isInOut());
56965703

56975704
// If parameter is an autoclosure, we need to make sure that:

trunk/lib/Sema/CSDiagnostics.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1760,6 +1760,14 @@ bool MissingCallFailure::diagnoseAsError() {
17601760
return true;
17611761
}
17621762

1763+
case ConstraintLocator::FunctionResult: {
1764+
path = path.drop_back();
1765+
if (path.back().getKind() != ConstraintLocator::AutoclosureResult)
1766+
break;
1767+
1768+
LLVM_FALLTHROUGH;
1769+
}
1770+
17631771
case ConstraintLocator::AutoclosureResult: {
17641772
auto &cs = getConstraintSystem();
17651773
auto loc = cs.getConstraintLocator(getRawAnchor(), path.drop_back(),

trunk/lib/Sema/CSSimplify.cpp

Lines changed: 39 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -973,30 +973,6 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments(
973973
auto *anchor = locator.getAnchor();
974974
assert(anchor && "locator without anchor expression?");
975975

976-
// Check whether argument of the call at given position refers to
977-
// parameter marked as `@autoclosure`. This function is used to
978-
// maintain source compatibility with Swift versions < 5,
979-
// previously examples like following used to type-check:
980-
//
981-
// func foo(_ x: @autoclosure () -> Int) {}
982-
// func bar(_ y: @autoclosure () -> Int) {
983-
// foo(y)
984-
// }
985-
auto isAutoClosureArg = [&](Expr *anchor, unsigned argIdx) -> bool {
986-
assert(anchor);
987-
988-
auto *argExpr = getArgumentExpr(anchor, argIdx);
989-
if (!argExpr)
990-
return false;
991-
992-
if (auto *DRE = dyn_cast<DeclRefExpr>(argExpr)) {
993-
if (auto *param = dyn_cast<ParamDecl>(DRE->getDecl()))
994-
return param->isAutoClosure();
995-
}
996-
997-
return false;
998-
};
999-
1000976
for (unsigned paramIdx = 0, numParams = parameterBindings.size();
1001977
paramIdx != numParams; ++paramIdx){
1002978
// Skip unfulfilled parameters. There's nothing to do for them.
@@ -1007,29 +983,33 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments(
1007983
const auto &param = params[paramIdx];
1008984
auto paramTy = param.getOldType();
1009985

1010-
if (param.isAutoClosure())
1011-
paramTy = paramTy->castTo<FunctionType>()->getResult();
1012-
1013986
// Compare each of the bound arguments for this parameter.
1014987
for (auto argIdx : parameterBindings[paramIdx]) {
1015988
auto loc = locator.withPathElement(LocatorPathElt::
1016989
getApplyArgToParam(argIdx,
1017990
paramIdx));
1018991
auto argTy = argsWithLabels[argIdx].getOldType();
1019992

1020-
// If parameter was marked as `@autoclosure` and argument
1021-
// is itself `@autoclosure` function type in Swift < 5,
1022-
// let's fix that up by making it look like argument is
1023-
// called implicitly.
1024-
if (param.isAutoClosure() &&
1025-
isAutoClosureArg(locator.getAnchor(), argIdx)) {
1026-
argTy = argTy->castTo<FunctionType>()->getResult();
1027-
cs.increaseScore(SK_FunctionConversion);
1028-
1029-
if (cs.getASTContext().isSwiftVersionAtLeast(5)) {
1030-
auto *fixLoc = cs.getConstraintLocator(loc);
1031-
if (cs.recordFix(AutoClosureForwarding::create(cs, fixLoc)))
1032-
return cs.getTypeMatchFailure(loc);
993+
bool matchingAutoClosureResult = param.isAutoClosure();
994+
if (param.isAutoClosure()) {
995+
auto &ctx = cs.getASTContext();
996+
auto *fnType = paramTy->castTo<FunctionType>();
997+
auto *argExpr = getArgumentExpr(locator.getAnchor(), argIdx);
998+
999+
// If the argument is not marked as @autoclosure or
1000+
// this is Swift version >= 5 where forwarding is not allowed,
1001+
// argument would always be wrapped into an implicit closure
1002+
// at the end, so we can safely match against result type.
1003+
if (ctx.isSwiftVersionAtLeast(5) || !isAutoClosureArgument(argExpr)) {
1004+
// In Swift >= 5 mode there is no @autoclosure forwarding,
1005+
// so let's match result types.
1006+
paramTy = fnType->getResult();
1007+
} else {
1008+
// Matching @autoclosure argument to @autoclosure parameter
1009+
// directly would mean introducting a function conversion
1010+
// in Swift <= 4 mode.
1011+
cs.increaseScore(SK_FunctionConversion);
1012+
matchingAutoClosureResult = false;
10331013
}
10341014
}
10351015

@@ -1040,7 +1020,7 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments(
10401020

10411021
cs.addConstraint(
10421022
subKind, argTy, paramTy,
1043-
param.isAutoClosure()
1023+
matchingAutoClosureResult
10441024
? loc.withPathElement(ConstraintLocator::AutoclosureResult)
10451025
: loc,
10461026
/*isFavored=*/false);
@@ -2187,6 +2167,18 @@ bool ConstraintSystem::repairFailures(
21872167
break;
21882168
}
21892169

2170+
case ConstraintLocator::FunctionResult: {
2171+
// `apply argument` -> `arg/param compare` ->
2172+
// `@autoclosure result` -> `function result`
2173+
if (path.size() > 3) {
2174+
const auto &elt = path[path.size() - 2];
2175+
if (elt.getKind() == ConstraintLocator::AutoclosureResult &&
2176+
repairByInsertingExplicitCall(lhs, rhs))
2177+
return true;
2178+
}
2179+
break;
2180+
}
2181+
21902182
case ConstraintLocator::AutoclosureResult: {
21912183
if (repairByInsertingExplicitCall(lhs, rhs))
21922184
return true;
@@ -6576,6 +6568,12 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
65766568
return result;
65776569
}
65786570

6571+
case FixKind::AutoClosureForwarding: {
6572+
if (recordFix(fix))
6573+
return SolutionKind::Error;
6574+
return matchTypes(type1, type2, matchKind, subflags, locator);
6575+
}
6576+
65796577
case FixKind::InsertCall:
65806578
case FixKind::RemoveReturn:
65816579
case FixKind::RemoveAddressOf:
@@ -6591,7 +6589,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
65916589
case FixKind::CoerceToCheckedCast:
65926590
case FixKind::RelabelArguments:
65936591
case FixKind::AddConformance:
6594-
case FixKind::AutoClosureForwarding:
65956592
case FixKind::RemoveUnwrap:
65966593
case FixKind::DefineMemberBasedOnUse:
65976594
case FixKind::AllowTypeOrInstanceMember:

trunk/lib/Sema/ConstraintSystem.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2666,6 +2666,18 @@ Expr *constraints::getArgumentExpr(Expr *expr, unsigned index) {
26662666
return cast<TupleExpr>(argExpr)->getElement(index);
26672667
}
26682668

2669+
bool constraints::isAutoClosureArgument(Expr *argExpr) {
2670+
if (!argExpr)
2671+
return false;
2672+
2673+
if (auto *DRE = dyn_cast<DeclRefExpr>(argExpr)) {
2674+
if (auto *param = dyn_cast<ParamDecl>(DRE->getDecl()))
2675+
return param->isAutoClosure();
2676+
}
2677+
2678+
return false;
2679+
}
2680+
26692681
void ConstraintSystem::generateConstraints(
26702682
SmallVectorImpl<Constraint *> &constraints, Type type,
26712683
ArrayRef<OverloadChoice> choices, DeclContext *useDC,

trunk/lib/Sema/ConstraintSystem.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3794,6 +3794,17 @@ Expr *simplifyLocatorToAnchor(ConstraintSystem &cs, ConstraintLocator *locator);
37943794
/// wasn't of one of the kinds listed above.
37953795
Expr *getArgumentExpr(Expr *expr, unsigned index);
37963796

3797+
// Check whether argument of the call at given position refers to
3798+
// parameter marked as `@autoclosure`. This function is used to
3799+
// maintain source compatibility with Swift versions < 5,
3800+
// previously examples like following used to type-check:
3801+
//
3802+
// func foo(_ x: @autoclosure () -> Int) {}
3803+
// func bar(_ y: @autoclosure () -> Int) {
3804+
// foo(y)
3805+
// }
3806+
bool isAutoClosureArgument(Expr *argExpr);
3807+
37973808
class DisjunctionChoice {
37983809
unsigned Index;
37993810
Constraint *Choice;

trunk/test/Compatibility/attr_autoclosure.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,10 @@ func passAutoClosureToEnumCase(_ fn: @escaping @autoclosure () -> Int) {
6262
// somewhere SILGen if `fn` doesn't have `@escaping`.
6363
let _: E = .baz(fn) // Ok
6464
}
65+
66+
do {
67+
func bar(_ fn: @autoclosure () -> (() -> Int)) {}
68+
func foo(_ fn: @autoclosure @escaping () -> (() -> Int)) {
69+
bar(fn) // Ok
70+
}
71+
}

trunk/test/attr/attr_autoclosure.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,3 +245,32 @@ protocol P_47586626 {
245245
func foo(_: @autoclosure F)
246246
func bar<T>(_: @autoclosure G<T>)
247247
}
248+
249+
func overloaded_autoclj<T>(_: @autoclosure () -> T) {}
250+
func overloaded_autoclj(_: @autoclosure () -> Int) {}
251+
252+
func autoclosure_param_returning_func_type() {
253+
func foo(_ fn: @autoclosure () -> (() -> Int)) {}
254+
func generic_foo<T>(_ fn: @autoclosure () -> T) {}
255+
256+
func bar_1(_ fn: @autoclosure @escaping () -> Int) { foo(fn) } // Ok
257+
func bar_2(_ fn: @autoclosure () -> Int) { foo(fn) } // expected-note {{parameter 'fn' is implicitly non-escaping}}
258+
// expected-error@-1 {{using non-escaping parameter 'fn' in a context expecting an @escaping closure}}
259+
func baz_1(_ fn: @autoclosure @escaping () -> Int) { generic_foo(fn) } // Ok (T is inferred as () -> Int)
260+
func baz_2(_ fn: @autoclosure @escaping () -> Int) { generic_foo(fn()) } // Ok (T is inferred as Int)
261+
func baz_3(_ fn: @autoclosure () -> Int) { generic_foo(fn) } // Fails because fn is not marked as @escaping
262+
// expected-error@-1 {{converting non-escaping value to 'T' may allow it to escape}}
263+
264+
// Let's make sure using `fn` as value works fine in presence of overloading
265+
func biz_1(_ fn: @autoclosure @escaping () -> Int) { overloaded_autoclj(fn) } // Ok
266+
func biz_2(_ fn: @autoclosure @escaping () -> Int) { overloaded_autoclj(fn()) } // Ok
267+
func biz_3(_ fn: @autoclosure () -> Int) { overloaded_autoclj(fn) } // Fails because fn is not marked as @escaping
268+
// expected-error@-1 {{add () to forward @autoclosure parameter}} {{67-67=()}}
269+
270+
func fiz(_: @autoclosure () -> (() -> Int)) {}
271+
272+
func biz_4(_ fn: @autoclosure @escaping () -> (() -> Int)) { fiz(fn) } // Can't forward in Swift >= 5 mode
273+
// expected-error@-1 {{add () to forward @autoclosure parameter}} {{70-70=()}}
274+
func biz_5(_ fn: @escaping () -> (() -> Int)) { fiz(fn) } // Can't forward in Swift >= 5 mode
275+
// expected-error@-1 {{add () to forward @autoclosure parameter}} {{57-57=()}}
276+
}

0 commit comments

Comments
 (0)