Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable SE-0413 "Typed Throws" by default #70677

Merged
merged 7 commits into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,49 @@
> **Note**\
> This is in reverse chronological order, so newer entries are added to the top.

## Swift 5.11

* [SE-0413][]:

Functions can now specify the type of error that they throw as part of the
function signature. For example:

```swift
func parseRecord(from string: String) throws(ParseError) -> Record { ... }
```

A call to `parseRecord(from:)` will either return a `Record` instance or throw
an error of type `ParseError`. For example, a `do..catch` block will infer
the `error` variable as being of type `ParseError`:

```swift
do {
let record = try parseRecord(from: myString)
} catch {
// error has type ParseError
}
```

Typed throws generalizes over throwing and non-throwing functions. A function
that is specified as `throws` (without an explicitly-specified error type) is
equivalent to one that specifies `throws(any Error)`, whereas a non-throwing
is equivalent to one that specifies `throws(Never)`. Calls to functions that
are `throws(Never)` are non-throwing.

Typed throws can also be used in generic functions to propagate error types
from parameters, in a manner that is more precise than `rethrows`. For
example, the `Sequence.map` operation can propagate the thrown error type from
its closure parameter, indicating that it only throws errors of the same type
as that closure does:

```swift
extension Sequence {
func map<T, E>(_ body: (Element) throws(E) -> T) throws(E) -> [T] { ... }
}
```

When given a non-throwing closure as a parameter, `map` will not throw.

* [#70065][]:

With the implementation of [SE-0110][], a closure parameter syntax consisting
Expand Down Expand Up @@ -9861,6 +9904,7 @@ using the `.dynamicType` member to retrieve the type of an expression should mig
[SE-0394]: https://github.com/apple/swift-evolution/blob/main/proposals/0394-swiftpm-expression-macros.md
[SE-0397]: https://github.com/apple/swift-evolution/blob/main/proposals/0397-freestanding-declaration-macros.md
[SE-0407]: https://github.com/apple/swift-evolution/blob/main/proposals/0407-member-macro-conformances.md
[SE-0413]: https://github.com/apple/swift-evolution/blob/main/proposals/0413-typed-throws.md
[#64927]: <https://github.com/apple/swift/issues/64927>
[#42697]: <https://github.com/apple/swift/issues/42697>
[#42728]: <https://github.com/apple/swift/issues/42728>
Expand Down
3 changes: 0 additions & 3 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -5231,9 +5231,6 @@ WARNING(no_throw_in_try,none,
WARNING(no_throw_in_do_with_catch,none,
"'catch' block is unreachable because no errors are thrown in 'do' block", ())

ERROR(experimental_typed_throws,none,
"typed throws is an experimental feature", ())

ERROR(thrown_type_not_error,none,
"thrown type %0 does not conform to the 'Error' protocol", (Type))

Expand Down
4 changes: 1 addition & 3 deletions include/swift/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ LANGUAGE_FEATURE(ParameterPacks, 393, "Value and type parameter packs", true)
SUPPRESSIBLE_LANGUAGE_FEATURE(LexicalLifetimes, 0, "@_eagerMove/@_noEagerMove/@_lexicalLifetimes annotations", true)
LANGUAGE_FEATURE(FreestandingMacros, 397, "freestanding declaration macros", true)
SUPPRESSIBLE_LANGUAGE_FEATURE(RetroactiveAttribute, 364, "@retroactive", true)
LANGUAGE_FEATURE(TypedThrows, 413, "Typed throws", true)

UPCOMING_FEATURE(ConciseMagicFile, 274, 6)
UPCOMING_FEATURE(ForwardTrailingClosures, 286, 6)
Expand Down Expand Up @@ -249,9 +250,6 @@ EXPERIMENTAL_FEATURE(Embedded, true)
/// Enables noncopyable generics
EXPERIMENTAL_FEATURE(NoncopyableGenerics, false)

/// Enables typed throws.
EXPERIMENTAL_FEATURE(TypedThrows, true)

/// Allow destructuring stored `let` bindings in structs.
EXPERIMENTAL_FEATURE(StructLetDestructuring, true)

Expand Down
1 change: 0 additions & 1 deletion lib/ASTGen/Sources/ASTGen/SourceFile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ extension Parser.ExperimentalFeatures {
}
}
mapFeature(.ThenStatements, to: .thenStatements)
mapFeature(.TypedThrows, to: .typedThrows)
mapFeature(.DoExpressions, to: .doExpressions)
mapFeature(.NonescapableTypes, to: .nonescapableTypes)
}
Expand Down
5 changes: 4 additions & 1 deletion lib/Sema/ConstraintSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ void ConstraintSystem::recordPotentialThrowSite(
ASTContext &ctx = getASTContext();

// Only record potential throw sites when typed throws is enabled.
if (!ctx.LangOpts.hasFeature(Feature::TypedThrows))
if (!ctx.LangOpts.hasFeature(Feature::FullTypedThrows))
return;

// Catch node location is determined by the source location.
Expand Down Expand Up @@ -432,6 +432,9 @@ Type ConstraintSystem::getCaughtErrorType(CatchNode catchNode) {
return getClosureType(closure)->getEffectiveThrownErrorTypeOrNever();
}

if (!ctx.LangOpts.hasFeature(Feature::FullTypedThrows))
return ctx.getErrorExistentialType();

// Handle inference of caught error types.

// Collect all of the potential throw sites for this catch node.
Expand Down
3 changes: 1 addition & 2 deletions lib/Sema/TypeCheckEffects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -663,8 +663,7 @@ static Expr *removeErasureToExistentialError(Expr *expr) {
return expr;

ASTContext &ctx = type->getASTContext();
if (!ctx.LangOpts.hasFeature(Feature::FullTypedThrows) ||
!ctx.LangOpts.hasFeature(Feature::TypedThrows))
if (!ctx.LangOpts.hasFeature(Feature::FullTypedThrows))
return expr;

// Look for an outer erasure expression.
Expand Down
18 changes: 12 additions & 6 deletions lib/Sema/TypeCheckPattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1239,7 +1239,9 @@ Pattern *TypeChecker::coercePatternToType(
} else if (auto MTT = diagTy->getAs<AnyMetatypeType>()) {
if (MTT->getInstanceType()->isAnyObject())
shouldRequireType = true;
} else if (diagTy->isStructurallyUninhabited()) {
} else if (diagTy->isStructurallyUninhabited() &&
!(options.contains(TypeResolutionFlags::SilenceNeverWarnings) &&
type->isNever())) {
shouldRequireType = true;
diag = isOptional ? diag::type_inferred_to_undesirable_type
: diag::type_inferred_to_uninhabited_type;
Expand Down Expand Up @@ -1428,11 +1430,15 @@ Pattern *TypeChecker::coercePatternToType(
if (type->hasError()) {
return nullptr;
}
diags
.diagnose(IP->getLoc(), diag::downcast_to_unrelated, type,
IP->getCastType())
.highlight(IP->getLoc())
.highlight(IP->getCastTypeRepr()->getSourceRange());

if (!(options.contains(TypeResolutionFlags::SilenceNeverWarnings) &&
type->isNever())) {
diags
.diagnose(IP->getLoc(), diag::downcast_to_unrelated, type,
IP->getCastType())
.highlight(IP->getLoc())
.highlight(IP->getCastTypeRepr()->getSourceRange());
}

IP->setCastKind(CheckedCastKind::ValueCast);
break;
Expand Down
8 changes: 6 additions & 2 deletions lib/Sema/TypeCheckStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1468,6 +1468,7 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
}

void checkCaseLabelItemPattern(CaseStmt *caseBlock, CaseLabelItem &labelItem,
CaseParentKind parentKind,
bool &limitExhaustivityChecks,
Type subjectType) {
Pattern *pattern = labelItem.getPattern();
Expand All @@ -1484,6 +1485,9 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
if (subjectType) {
auto contextualPattern = ContextualPattern::forRawPattern(pattern, DC);
TypeResolutionOptions patternOptions(TypeResolverContext::InExpression);
if (parentKind == CaseParentKind::DoCatch)
patternOptions |= TypeResolutionFlags::SilenceNeverWarnings;

auto coercedPattern = TypeChecker::coercePatternToType(
contextualPattern, subjectType, patternOptions);
if (coercedPattern)
Expand Down Expand Up @@ -1584,8 +1588,8 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
for (auto &labelItem : caseLabelItemArray) {
// Resolve the pattern in our case label if it has not been resolved and
// check that our var decls follow invariants.
checkCaseLabelItemPattern(caseBlock, labelItem, limitExhaustivityChecks,
subjectType);
checkCaseLabelItemPattern(caseBlock, labelItem, parentKind,
limitExhaustivityChecks, subjectType);

// Check the guard expression, if present.
if (auto *guard = labelItem.getGuardExpr()) {
Expand Down
23 changes: 0 additions & 23 deletions lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3715,11 +3715,6 @@ NeverNullType TypeResolver::resolveASTFunctionType(
Type thrownTy;
if (auto thrownTypeRepr = repr->getThrownTypeRepr()) {
ASTContext &ctx = getASTContext();
if (!ctx.LangOpts.hasFeature(Feature::TypedThrows)) {
diagnoseInvalid(
thrownTypeRepr, thrownTypeRepr->getLoc(), diag::experimental_typed_throws);
}

auto thrownTypeOptions = options.withoutContext();
thrownTy = resolveType(thrownTypeRepr, thrownTypeOptions);
if (thrownTy->hasError()) {
Expand Down Expand Up @@ -5691,10 +5686,6 @@ Type ExplicitCaughtTypeRequest::evaluate(
}

// We have an explicit thrown error type, so resolve it.
if (!ctx.LangOpts.hasFeature(Feature::TypedThrows)) {
ctx.Diags.diagnose(thrownTypeRepr->getLoc(), diag::experimental_typed_throws);
}

auto options = TypeResolutionOptions(TypeResolverContext::None);
if (func->preconcurrency())
options |= TypeResolutionFlags::Preconcurrency;
Expand All @@ -5710,11 +5701,6 @@ Type ExplicitCaughtTypeRequest::evaluate(
if (auto closure = catchNode.dyn_cast<ClosureExpr *>()) {
// Explicit thrown error type.
if (auto thrownTypeRepr = closure->getExplicitThrownTypeRepr()) {
if (!ctx.LangOpts.hasFeature(Feature::TypedThrows)) {
ctx.Diags.diagnose(thrownTypeRepr->getLoc(),
diag::experimental_typed_throws);
}

return TypeResolution::resolveContextualType(
thrownTypeRepr, closure,
TypeResolutionOptions(TypeResolverContext::None),
Expand All @@ -5736,18 +5722,9 @@ Type ExplicitCaughtTypeRequest::evaluate(
// A do..catch block with no explicit 'throws' annotation will infer
// the thrown error type.
if (doCatch->getThrowsLoc().isInvalid()) {
// Prior to typed throws, the do..catch always throws 'any Error'.
if (!ctx.LangOpts.hasFeature(Feature::TypedThrows))
return ctx.getErrorExistentialType();

return Type();
}

if (!ctx.LangOpts.hasFeature(Feature::TypedThrows)) {
ctx.Diags.diagnose(doCatch->getThrowsLoc(), diag::experimental_typed_throws);
return ctx.getErrorExistentialType();
}

auto typeRepr = doCatch->getCaughtTypeRepr();

// If there is no explicitly-specified thrown error type, it's 'any Error'.
Expand Down
4 changes: 4 additions & 0 deletions lib/Sema/TypeCheckType.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ enum class TypeResolutionFlags : uint16_t {

/// Whether this is a resolution based on a pack reference.
FromPackReference = 1 << 12,

/// Whether to suppress warnings about conversions from and bindings of type
/// Never
SilenceNeverWarnings = 1 << 13,
};

/// Type resolution contexts that require special handling.
Expand Down
2 changes: 1 addition & 1 deletion test/Concurrency/typed_throws.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-typecheck-verify-swift -enable-experimental-feature TypedThrows
// RUN: %target-typecheck-verify-swift

// REQUIRES: concurrency

Expand Down
2 changes: 1 addition & 1 deletion test/Generics/typed_throws.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-typecheck-verify-swift -debug-generic-signatures -enable-experimental-feature TypedThrows 2>&1 | %FileCheck %s
// RUN: %target-typecheck-verify-swift -debug-generic-signatures 2>&1 | %FileCheck %s

protocol P1 {
associatedtype A
Expand Down
18 changes: 9 additions & 9 deletions test/IDE/complete_exception.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=INSIDE_CATCH_ERR_DOT1 | %FileCheck %s -check-prefix=ERROR_DOT
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=INSIDE_CATCH_ERR_DOT2 | %FileCheck %s -check-prefix=ERROR_DOT
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=INSIDE_CATCH_ERR_DOT3 | %FileCheck %s -check-prefix=NSERROR_DOT
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=INSIDE_CATCH_ERR_DOT4 | %FileCheck %s -check-prefix=INT_DOT
// RUNFIXME: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=INSIDE_CATCH_ERR_DOT4 | %FileCheck %s -check-prefix=INT_DOT

// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=TOP_LEVEL_INSIDE_CATCH1 > %t.top_level_inside_catch1
// RUN: %FileCheck %s -check-prefix=STMT < %t.top_level_inside_catch1
Expand Down Expand Up @@ -71,10 +71,10 @@ func getNSError() -> NSError { return NSError(domain: "", code: 1, userInfo: [:]
func test001() {
do {} catch #^CATCH1^#

// CATCH1-DAG: Decl[Enum]/CurrModule/TypeRelation[Convertible]: Error4[#Error4#]; name=Error4{{$}}
// CATCH1-DAG: Decl[Class]/CurrModule/TypeRelation[Convertible]: Error3[#Error3#]; name=Error3{{$}}
// CATCH1-DAG: Decl[Class]/CurrModule/TypeRelation[Convertible]: Error2[#Error2#]; name=Error2{{$}}
// CATCH1-DAG: Decl[Class]/CurrModule/TypeRelation[Convertible]: Error1[#Error1#]; name=Error1{{$}}
// CATCH1-DAG: Decl[Enum]/CurrModule: Error4[#Error4#]; name=Error4{{$}}
// CATCH1-DAG: Decl[Class]/CurrModule: Error3[#Error3#]; name=Error3{{$}}
// CATCH1-DAG: Decl[Class]/CurrModule: Error2[#Error2#]; name=Error2{{$}}
// CATCH1-DAG: Decl[Class]/CurrModule: Error1[#Error1#]; name=Error1{{$}}
// CATCH1-DAG: Keyword[let]/None: let{{; name=.+$}}
// CATCH1-DAG: Decl[Class]/CurrModule: NoneError1[#NoneError1#]; name=NoneError1{{$}}
// CATCH1-DAG: Decl[Class]/OtherModule[Foundation]/IsSystem: NSError[#NSError#]{{; name=.+$}}
Expand Down Expand Up @@ -147,14 +147,14 @@ func test006() {
} catch {
#^INSIDE_CATCH1^#
}
// IMPLICIT_ERROR: Decl[LocalVar]/Local: error[#any Error#]; name=error
// IMPLICIT_ERROR: Decl[LocalVar]/Local: error[#Never#]; name=error
}
func test007() {
do {
} catch let e {
#^INSIDE_CATCH2^#
}
// EXPLICIT_ERROR_E: Decl[LocalVar]/Local: e[#any Error#]; name=e
// EXPLICIT_ERROR_E: Decl[LocalVar]/Local: e[#Never#]; name=e
}
func test008() {
do {
Expand All @@ -170,7 +170,7 @@ func test009() {
}

// FIXME: we're getting parentheses around the type when it's unnamed...
// EXPLICIT_ERROR_PAYLOAD_I: Decl[LocalVar]/Local: i[#(Int32)#]; name=i
// EXPLICIT_ERROR_PAYLOAD_I: Decl[LocalVar]/Local: i[#<<error type>>#]; name=i
}
func test010() {
do {
Expand All @@ -195,7 +195,7 @@ func test012() {
error.#^INSIDE_CATCH_ERR_DOT1^#
}
}
// ERROR_DOT: Keyword[self]/CurrNominal: self[#any Error#]; name=self
// ERROR_DOT: Keyword[self]/CurrNominal: self[#Never#]; name=self
func test013() {
do {
} catch let e {
Expand Down
6 changes: 3 additions & 3 deletions test/IRGen/typed_throws.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// RUN: %target-swift-frontend -primary-file %s -emit-ir -enable-experimental-feature TypedThrows -disable-availability-checking -runtime-compatibility-version none -target %module-target-future | %FileCheck %s --check-prefix=CHECK-MANGLE
// RUN: %target-swift-frontend -primary-file %s -emit-ir -disable-availability-checking -runtime-compatibility-version none -target %module-target-future | %FileCheck %s --check-prefix=CHECK-MANGLE

// RUN: %target-swift-frontend -primary-file %s -emit-ir -enable-experimental-feature TypedThrows -disable-availability-checking -runtime-compatibility-version 5.8 -disable-concrete-type-metadata-mangled-name-accessors | %FileCheck %s --check-prefix=CHECK-NOMANGLE
// RUN: %target-swift-frontend -primary-file %s -emit-ir -disable-availability-checking -runtime-compatibility-version 5.8 -disable-concrete-type-metadata-mangled-name-accessors | %FileCheck %s --check-prefix=CHECK-NOMANGLE

// RUN: %target-swift-frontend -primary-file %s -emit-ir -enable-experimental-feature TypedThrows | %FileCheck %s --check-prefix=CHECK
// RUN: %target-swift-frontend -primary-file %s -emit-ir | %FileCheck %s --check-prefix=CHECK

// XFAIL: CPU=arm64e
// REQUIRES: PTRSIZE=64
Expand Down
2 changes: 1 addition & 1 deletion test/IRGen/typed_throws_exec.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %empty-directory(%t)
// RUN: %target-build-swift -module-name=test -enable-experimental-feature TypedThrows %s -o %t/a.out
// RUN: %target-build-swift -module-name=test %s -o %t/a.out
// RUN: %target-codesign %t/a.out
// RUN: %target-run %t/a.out | %FileCheck %s
// REQUIRES: executable_test
Expand Down
2 changes: 1 addition & 1 deletion test/IRGen/typed_throws_thunks.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-swift-frontend -primary-file %s -emit-irgen -enable-experimental-feature TypedThrows -disable-availability-checking -runtime-compatibility-version none -target %module-target-future -enable-library-evolution | %FileCheck %s --check-prefix=CHECK
// RUN: %target-swift-frontend -primary-file %s -emit-irgen -disable-availability-checking -runtime-compatibility-version none -target %module-target-future -enable-library-evolution | %FileCheck %s --check-prefix=CHECK

// REQUIRES: PTRSIZE=64
// UNSUPPORTED: CPU=arm64e
Expand Down
4 changes: 2 additions & 2 deletions test/ModuleInterface/typed_throws.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %s -module-name Test -enable-experimental-feature TypedThrows
// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -module-name Test -enable-experimental-feature TypedThrows
// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %s -module-name Test
// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -module-name Test
// RUN: %FileCheck %s < %t.swiftinterface

public enum MyError: Error {
Expand Down
6 changes: 4 additions & 2 deletions test/Parse/errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ func one() {
do {

} catch { // expected-warning {{'catch' block is unreachable because no errors are thrown in 'do' block}}
let error2 = error
let error2 = error // expected-warning{{constant 'error2' inferred to have type 'Never', which is an enum with no cases}}
// expected-note@-1{{add an explicit type annotation to silence this warning}}
}

do {
} catch where true { // expected-warning {{'catch' block is unreachable because no errors are thrown in 'do' block}}
let error2 = error
let error2 = error // expected-warning{{constant 'error2' inferred to have type 'Never', which is an enum with no cases}}
// expected-note@-1{{add an explicit type annotation to silence this warning}}
} catch {
}

Expand Down
2 changes: 1 addition & 1 deletion test/Parse/typed_throws.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-typecheck-verify-swift -swift-version 5 -module-name test -enable-experimental-feature TypedThrows
// RUN: %target-typecheck-verify-swift -swift-version 5 -module-name test

// Parsing support for typed throws.

Expand Down
2 changes: 1 addition & 1 deletion test/Runtime/demangleToMetadata.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %empty-directory(%t)
// RUN: %target-build-swift -Xfrontend -disable-availability-checking -parse-stdlib -enable-experimental-feature TypedThrows %s -module-name main -o %t/a.out
// RUN: %target-build-swift -Xfrontend -disable-availability-checking -parse-stdlib %s -module-name main -o %t/a.out
// RUN: %target-codesign %t/a.out
// RUN: %target-run %t/a.out
// REQUIRES: executable_test
Expand Down
2 changes: 1 addition & 1 deletion test/SILGen/typed_throws.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-swift-emit-silgen %s -enable-experimental-feature TypedThrows | %FileCheck %s
// RUN: %target-swift-emit-silgen %s | %FileCheck %s

enum MyError: Error {
case fail
Expand Down
2 changes: 1 addition & 1 deletion test/SILGen/typed_throws_generic.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-swift-emit-silgen %s -enable-experimental-feature TypedThrows -enable-experimental-feature FullTypedThrows | %FileCheck %s
// RUN: %target-swift-emit-silgen %s -enable-experimental-feature FullTypedThrows | %FileCheck %s

public func genericThrow<E>(e: E) throws(E) {
throw e
Expand Down
Loading