Skip to content

Commit f1831fb

Browse files
committed
Sema: Teach rethrows checking about 'nil' default arguments
In Swift 5.4, this worked: func foo(_: (() throws -> ())? = nil) rethrows {} foo() // no 'try' needed However, this was an accident, because this was also accepted: func foo(_: (() throws -> ())? = { throw ... }) rethrows {} foo() // 'try' *should* be required here This got fixed at some point recently, but since people rely on the old case working for 'nil', let's add back a check for a 'nil' default parameter. Fixes rdar://problem/76169080.
1 parent c9f550c commit f1831fb

File tree

2 files changed

+28
-1
lines changed

2 files changed

+28
-1
lines changed

lib/Sema/TypeCheckEffects.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1244,7 +1244,16 @@ class ApplyClassifier {
12441244
Classification classifyArgument(Expr *arg, Type paramType, EffectKind kind) {
12451245
arg = arg->getValueProvidingExpr();
12461246

1247-
if (isa<DefaultArgumentExpr>(arg)) {
1247+
if (auto *defaultArg = dyn_cast<DefaultArgumentExpr>(arg)) {
1248+
// Special-case a 'nil' default argument, which is known not to throw.
1249+
if (defaultArg->isCallerSide()) {
1250+
auto *callerSideArg = defaultArg->getCallerSideDefaultExpr();
1251+
if (isa<NilLiteralExpr>(callerSideArg)) {
1252+
if (callerSideArg->getType()->getOptionalObjectType())
1253+
return Classification();
1254+
}
1255+
}
1256+
12481257
return classifyArgumentByType(arg->getType(),
12491258
PotentialEffectReason::forDefaultClosure(),
12501259
kind);

test/decl/func/rethrows.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,3 +628,21 @@ func throwableDefaultRethrows(_ f: () throws -> () = { throw SomeError.Badness }
628628
// This should always emit a diagnostic because we can statically know that default argument can throw.
629629
throwableDefaultRethrows() // expected-error {{call can throw but is not marked with 'try'}}
630630
// expected-note@-1 {{call is to 'rethrows' function, but a defaulted argument function can throw}}
631+
632+
// rdar://76169080 - rethrows -vs- Optional default arguments
633+
func optionalRethrowsDefaultArg1(_: (() throws -> ())? = nil) rethrows {}
634+
635+
func callsOptionalRethrowsDefaultArg1() throws {
636+
optionalRethrowsDefaultArg1()
637+
optionalRethrowsDefaultArg1(nil)
638+
try optionalRethrowsDefaultArg1 { throw SomeError.Badness }
639+
}
640+
641+
func optionalRethrowsDefaultArg2(_: (() throws -> ())? = { throw SomeError.Badness }) rethrows {}
642+
643+
func callsOptionalRethrowsDefaultArg2() throws {
644+
optionalRethrowsDefaultArg2() // expected-error {{call can throw but is not marked with 'try'}}
645+
// expected-note@-1 {{call is to 'rethrows' function, but a defaulted argument function can throw}}
646+
optionalRethrowsDefaultArg2(nil)
647+
try optionalRethrowsDefaultArg2 { throw SomeError.Badness }
648+
}

0 commit comments

Comments
 (0)