Skip to content

Commit b8cc015

Browse files
committed
Fix some issues in handling of withoutActuallyEscaping.
We need to strip inout/lvalue before casting the second parameter's type to FunctionType. There were also some verification issues and the fact that we weren't allowing already-escaping closures to be passed to it (which is not useful, but shouldn't result in an error and really awful diagnostic). We can potentially look at diagnosing this with a warning at some point in the future. Fixes rdar://problem/32239354.
1 parent 34ad596 commit b8cc015

File tree

4 files changed

+72
-24
lines changed

4 files changed

+72
-24
lines changed

lib/AST/ASTVerifier.cpp

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1839,35 +1839,51 @@ class Verifier : public ASTWalker {
18391839
Out << "MakeTemporarilyEscapableExpr type does not match subexpression";
18401840
abort();
18411841
}
1842-
1843-
// Closure and opaque value should both be functions, with the closure
1844-
// noescape and the opaque value escapable but otherwise matching.
1845-
auto closureFnTy = E->getNonescapingClosureValue()->getType()
1846-
->getAs<FunctionType>();
1847-
if (!closureFnTy) {
1848-
Out << "MakeTemporarilyEscapableExpr closure type is not a closure";
1842+
1843+
auto call = dyn_cast<CallExpr>(E->getSubExpr());
1844+
if (!call) {
1845+
Out << "MakeTemporarilyEscapableExpr subexpression is not a call\n";
18491846
abort();
18501847
}
1851-
auto opaqueValueFnTy = E->getOpaqueValue()->getType()
1852-
->getAs<FunctionType>();
1853-
if (!opaqueValueFnTy) {
1854-
Out<<"MakeTemporarilyEscapableExpr opaque value type is not a closure";
1848+
1849+
auto callFnTy = call->getFn()->getType()->getAs<FunctionType>();
1850+
if (!callFnTy) {
1851+
Out << "MakeTemporarilyEscapableExpr call does not call function\n";
18551852
abort();
18561853
}
1857-
if (!closureFnTy->isNoEscape()) {
1858-
Out << "MakeTemporarilyEscapableExpr closure type should be noescape";
1854+
if (!callFnTy->getExtInfo().isNoEscape()) {
1855+
Out << "MakeTemporarilyEscapableExpr called function is not noescape\n";
18591856
abort();
18601857
}
1861-
if (opaqueValueFnTy->isNoEscape()) {
1862-
Out << "MakeTemporarilyEscapableExpr opaque value type should be "
1863-
"escaping";
1858+
1859+
auto callArgTy = call->getArg()->getType()->getAs<FunctionType>();
1860+
if (!callArgTy) {
1861+
Out << "MakeTemporarilyEscapableExpr call argument is not a function\n";
1862+
abort();
1863+
}
1864+
1865+
// Closure and opaque value should both be functions, with the closure
1866+
// noescape and the opaque value escapable but otherwise matching.
1867+
auto closureFnTy =
1868+
E->getNonescapingClosureValue()->getType()->getAs<FunctionType>();
1869+
if (!closureFnTy) {
1870+
Out << "MakeTemporarilyEscapableExpr closure type is not a closure\n";
1871+
abort();
1872+
}
1873+
auto opaqueValueFnTy =
1874+
E->getOpaqueValue()->getType()->getAs<FunctionType>();
1875+
if (!opaqueValueFnTy) {
1876+
Out << "MakeTemporarilyEscapableExpr opaque value type is not a "
1877+
"closure\n";
18641878
abort();
18651879
}
1866-
if (!closureFnTy->isEqual(
1867-
opaqueValueFnTy->withExtInfo(opaqueValueFnTy->getExtInfo()
1868-
.withNoEscape()))) {
1880+
auto closureFnNoEscape =
1881+
closureFnTy->withExtInfo(closureFnTy->getExtInfo().withNoEscape());
1882+
auto opaqueValueNoEscape = opaqueValueFnTy->withExtInfo(
1883+
opaqueValueFnTy->getExtInfo().withNoEscape());
1884+
if (!closureFnNoEscape->isEqual(opaqueValueNoEscape)) {
18691885
Out << "MakeTemporarilyEscapableExpr closure and opaque value type "
1870-
"don't match";
1886+
"don't match\n";
18711887
abort();
18721888
}
18731889
}

lib/Sema/CSApply.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6745,7 +6745,8 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
67456745
assert(arg->getNumElements() == 2 && "should have two arguments");
67466746
auto nonescaping = arg->getElements()[0];
67476747
auto body = arg->getElements()[1];
6748-
auto bodyFnTy = cs.getType(body)->castTo<FunctionType>();
6748+
auto bodyTy = cs.getType(body)->getLValueOrInOutObjectType();
6749+
auto bodyFnTy = bodyTy->castTo<FunctionType>();
67496750
auto escapableType = bodyFnTy->getInput();
67506751
auto resultType = bodyFnTy->getResult();
67516752

lib/Sema/CSSimplify.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3682,9 +3682,6 @@ ConstraintSystem::simplifyEscapableFunctionOfConstraint(
36823682

36833683
type2 = getFixedTypeRecursive(type2, flags, /*wantRValue=*/true);
36843684
if (auto fn2 = type2->getAs<FunctionType>()) {
3685-
// We should have the noescape end of the relation.
3686-
if (!fn2->getExtInfo().isNoEscape())
3687-
return SolutionKind::Error;
36883685
// Solve forward by binding the other type variable to the escapable
36893686
// variation of this type.
36903687
auto fn1 = fn2->withExtInfo(fn2->getExtInfo().withNoEscape(false));
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %target-swift-frontend -module-name main -typecheck -swift-version 3 %s
2+
// RUN: %target-swift-frontend -module-name main -typecheck -swift-version 4 %s
3+
4+
// These tests are split out to ensure that we run the AST verifier's
5+
// special post-type-checked verifications, which don't currently
6+
// happen if any errors occur anywhere during compilation.
7+
8+
func rdar32239354_1(_ fn: () -> Void) {
9+
var other: (() -> Void) -> Void = { _ in }
10+
11+
withoutActuallyEscaping(fn, do: other)
12+
// Reassign to avoid warning about changing this to a let, since we
13+
// need this to be a var to trigger the original issue.
14+
other = { _ in }
15+
}
16+
17+
func rdar32239354_2(_ fn: () -> Void, other: inout (() -> Void) -> Void) {
18+
withoutActuallyEscaping(fn, do: other)
19+
}
20+
21+
func testVariations(
22+
_ no_escape: () -> (),
23+
_ escape: @escaping () -> (),
24+
_ takesFn: (()->()) -> ()->()
25+
) -> () -> () {
26+
withoutActuallyEscaping(no_escape) { _ in }
27+
withoutActuallyEscaping({}) { _ in }
28+
withoutActuallyEscaping(escape) { _ in }
29+
_ = withoutActuallyEscaping(no_escape, do: takesFn)
30+
_ = withoutActuallyEscaping(escape, do: takesFn)
31+
_ = withoutActuallyEscaping(no_escape) {
32+
return takesFn($0)
33+
}
34+
}

0 commit comments

Comments
 (0)