Skip to content

Commit

Permalink
Merge pull request #1642 from ahoppen/SR-317-Optional-Throwing-Parame…
Browse files Browse the repository at this point in the history
…teter-Rethrows

[Sema] SR-317: Allow rethrowing functions to take an optional function parameter
  • Loading branch information
DougGregor committed Mar 14, 2016
2 parents c7dfed7 + 3f115d4 commit 2293d28
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 3 deletions.
2 changes: 1 addition & 1 deletion lib/Sema/TypeCheckAttr.cpp
Expand Up @@ -1237,7 +1237,7 @@ void AttributeChecker::visitRethrowsAttr(RethrowsAttr *attr) {
auto fn = cast<AbstractFunctionDecl>(D);
for (auto paramList : fn->getParameterLists()) {
for (auto param : *paramList)
if (hasThrowingFunctionParameter(param->getType()->getCanonicalType()))
if (hasThrowingFunctionParameter(param->getType()->lookThroughAllAnyOptionalTypes()->getCanonicalType()))
return;
}

Expand Down
14 changes: 12 additions & 2 deletions lib/Sema/TypeCheckError.cpp
Expand Up @@ -136,6 +136,16 @@ class AbstractFunction {
static AbstractFunction decomposeFunction(Expr *fn) {
assert(fn->getValueProvidingExpr() == fn);

// Look through Optional unwraps
while (true) {
if (auto conversion = dyn_cast<ForceValueExpr>(fn)) {
fn = conversion->getSubExpr()->getValueProvidingExpr();
} else if (auto conversion = dyn_cast<BindOptionalExpr>(fn)) {
fn = conversion->getSubExpr()->getValueProvidingExpr();
} else {
break;
}
}
// Look through function conversions.
while (auto conversion = dyn_cast<FunctionConversionExpr>(fn)) {
fn = conversion->getSubExpr()->getValueProvidingExpr();
Expand Down Expand Up @@ -480,7 +490,7 @@ class ApplyClassifier {

Classification classifyThrowingParameterBody(ParamDecl *param,
PotentialReason reason) {
assert(param->getType()->castTo<AnyFunctionType>()->throws());
assert(param->getType()->lookThroughAllAnyOptionalTypes()->castTo<AnyFunctionType>()->throws());

// If we're currently doing rethrows-checking on the body of the
// function which declares the parameter, it's rethrowing-only.
Expand Down Expand Up @@ -660,7 +670,7 @@ class ApplyClassifier {

// Otherwise, if the original parameter type was not a throwing
// function type, it does not contribute to 'rethrows'.
auto paramFnType = paramType->getAs<AnyFunctionType>();
auto paramFnType = paramType->lookThroughAllAnyOptionalTypes()->getAs<AnyFunctionType>();
if (!paramFnType || !paramFnType->throws())
return Classification();

Expand Down
29 changes: 29 additions & 0 deletions test/decl/func/rethrows.swift
Expand Up @@ -313,6 +313,35 @@ func testGenericMethodCallACHandled<P: MyProto>(s: P) throws {
try P.static_callAC(raise())
}

/** Optional closure parameters */

func testForceUnwrappedOptionalFunctionParameter(f: (() throws -> Void)?) rethrows {
try f!()
}

func testBindOptionalFunctionParameter(f: (() throws -> Void)?) rethrows {
try f?()
}

func testImplicitlyUnwrappedFunctionParameter(f: (() throws -> Void)!) rethrows {
if f != nil {
try f()
}
}

func throwingFunc() throws {}

func nonThrowingFunc() {}

try testBindOptionalFunctionParameter(throwingFunc)
testBindOptionalFunctionParameter(nonThrowingFunc)
testBindOptionalFunctionParameter(nil)

try testImplicitlyUnwrappedFunctionParameter(throwingFunc)
testImplicitlyUnwrappedFunctionParameter(nonThrowingFunc)
testImplicitlyUnwrappedFunctionParameter(nil)


/** Miscellaneous bugs **/

// rdar://problem/21967164 - Non-throwing closures are incorrectly marked as throwing in rethrow contexts
Expand Down

0 comments on commit 2293d28

Please sign in to comment.