Skip to content

Commit 9f5a754

Browse files
committed
[Sema] Ban placeholders in typed throws
This never worked correctly and would crash in SILGen, ban the use of placeholder types. While here, ensure we replace any ErrorTypes with holes when solving the closure in the constraint system.
1 parent 71f8e68 commit 9f5a754

File tree

5 files changed

+29
-5
lines changed

5 files changed

+29
-5
lines changed

lib/Sema/CSGen.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2542,8 +2542,11 @@ namespace {
25422542
Type thrownErrorTy = [&] {
25432543
// Explicitly-specified thrown type.
25442544
if (closure->getExplicitThrownTypeRepr()) {
2545-
if (Type explicitType = closure->getExplicitThrownType())
2546-
return explicitType;
2545+
if (Type explicitType = closure->getExplicitThrownType()) {
2546+
// The thrown type may have errors, open as placeholders if needed.
2547+
return CS.replaceInferableTypesWithTypeVars(explicitType,
2548+
thrownErrorLocator);
2549+
}
25472550
}
25482551

25492552
// Explicitly-specified 'throws' without a type is untyped throws.

lib/Sema/TypeCheckType.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6999,7 +6999,7 @@ Type ExplicitCaughtTypeRequest::evaluate(
69996999

70007000
return TypeResolution::forInterface(func, options,
70017001
/*unboundTyOpener*/ nullptr,
7002-
PlaceholderType::get,
7002+
/*placeholderOpener*/ nullptr,
70037003
/*packElementOpener*/ nullptr)
70047004
.resolveType(thrownTypeRepr);
70057005
}
@@ -7011,7 +7011,7 @@ Type ExplicitCaughtTypeRequest::evaluate(
70117011
return TypeResolution::resolveContextualType(
70127012
thrownTypeRepr, closure,
70137013
TypeResolutionOptions(TypeResolverContext::None),
7014-
/*unboundTyOpener*/ nullptr, PlaceholderType::get,
7014+
/*unboundTyOpener*/ nullptr, /*placeholderOpener*/ nullptr,
70157015
/*packElementOpener*/ nullptr);
70167016
}
70177017

@@ -7045,7 +7045,7 @@ Type ExplicitCaughtTypeRequest::evaluate(
70457045
return TypeResolution::resolveContextualType(
70467046
typeRepr, doCatch->getDeclContext(),
70477047
TypeResolutionOptions(TypeResolverContext::None),
7048-
/*unboundTyOpener*/ nullptr, PlaceholderType::get,
7048+
/*unboundTyOpener*/ nullptr, /*placeholderOpener*/ nullptr,
70497049
/*packElementOpener*/ nullptr);
70507050
}
70517051

test/decl/func/typed_throws.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,3 +216,8 @@ struct NotAnError<T> {}
216216

217217
func badThrowingFunctionType<T>(_: () throws(NotAnError<T>) -> ()) {}
218218
// expected-error@-1 {{thrown type 'NotAnError<T>' does not conform to the 'Error' protocol}}
219+
220+
struct GenericError<T>: Error {}
221+
222+
func placeholderThrowing1() throws(_) {} // expected-error {{type placeholder not allowed here}}
223+
func placeholderThrowing2() throws(GenericError<_>) {} // expected-error {{type placeholder not allowed here}}

test/expr/closure/typed_throws.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ enum MyBadError {
88
case fail
99
}
1010

11+
struct GenericError<T>: Error {}
12+
1113
func testClosures() {
1214
let c1 = { () throws(MyError) in
1315
throw .fail
@@ -36,5 +38,8 @@ func testClosures() {
3638
let c2 = { throw MyError.fail }
3739
let _: Int = c2
3840
// expected-error@-1{{cannot convert value of type '() throws -> ()'}}
41+
42+
_ = { () throws(_) in } // expected-error {{type placeholder not allowed here}}
43+
_ = { () throws(GenericError<_>) in } // expected-error {{type placeholder not allowed here}}
3944
}
4045

test/stmt/typed_throws.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ case dogAteIt
1212
case forgot
1313
}
1414

15+
struct GenericError<T>: Error {}
16+
1517
func processMyError(_: MyError) { }
1618

1719
func doSomething() throws(MyError) { }
@@ -418,3 +420,12 @@ func testSequenceExpr() async throws(Never) {
418420
try true ? 0 : try! getInt() ~~~ getInt()
419421
// expected-error@-1 {{'try!' following conditional operator does not cover everything to its right}}
420422
}
423+
424+
func testPlaceholder() {
425+
do throws(_) {} catch {}
426+
// expected-error@-1 {{type placeholder not allowed here}}
427+
// expected-warning@-2 {{'catch' block is unreachable because no errors are thrown in 'do' block}}
428+
do throws(GenericError<_>) {} catch {}
429+
// expected-error@-1 {{type placeholder not allowed here}}
430+
// expected-warning@-2 {{'catch' block is unreachable because no errors are thrown in 'do' block}}
431+
}

0 commit comments

Comments
 (0)