mirror of
https://github.com/apple/swift.git
synced 2026-10-20 19:13:47 +02:00
A `try_apply` whose callee's error result is uninhabited can never take
its error branch. Turn it into `apply [nothrow]` and let the dead-block
cleanup remove the error block.
This mostly shows up in Embedded Swift, which specializes generics at
-Onone: a `rethrows`-shaped `throws(E)` function specialized for `E ==
Never` keeps the rethrow, and IRGen has to emit that as an unconditional
trap ("Never can't be initialized") reached by an equally dead test of
the error register. Calling `withTemporaryAllocation` or `Optional.map`
was enough to get one per call site.
Enums which are resilient from the caller's point of view are excluded,
since a case-less non-frozen enum can gain cases in a future version of
its module.
`TryApplyInst` is both `OnoneSimplifiable` (so
`MandatoryPerformanceOptimizations` gets it, i.e. Embedded `-Onone`) and
`SILCombineSimplifiable` (so `-O` gets it without depending on the
inliner).
The predicate is `FunctionConvention.hasUninhabitedErrorResult(in:)`,
written in Swift over low-level bridges
(`TypeProperties.isStructurallyUninhabited`,
`EnumDecl.hasCasesUnavailableDuringLowering`,
`EnumDecl.isEffectivelyExhaustive`). `ResultInfo.getReturnValueType` now
takes the function type the result belongs to; it used to hardcode the
enclosing function's lowered type, which is wrong for a result of an
apply site's substituted callee type (it had no prior callers).
Two existing tests change behaviour because their error enums are
genuinely case-less: closure_lifetime_fixup's `Optional.map<_, Never,
_>` call is now an `apply`, and devirt_class_witness_method's local
`enum Error` gets a case so that 'caller2' keeps testing a throwing
witness call.
39 lines
1.5 KiB
Swift
39 lines
1.5 KiB
Swift
// RUN: %empty-directory(%t)
|
|
// RUN: split-file %s %t
|
|
|
|
/// Lib built with library evolution: `NoCases` can gain cases in a future version.
|
|
// RUN: %target-swift-frontend -emit-module -enable-library-evolution -swift-version 6 \
|
|
// RUN: -module-name Lib %t/Lib.swift -emit-module-path %t/Lib.swiftmodule
|
|
// RUN: %target-swift-frontend -emit-sil -O -swift-version 6 -I %t -module-name Client \
|
|
// RUN: %t/Client.swift | %FileCheck %s -check-prefix=RESILIENT
|
|
|
|
/// The same Lib without library evolution: `NoCases` is exhaustive, so it stays uninhabited.
|
|
// RUN: %target-swift-frontend -emit-module -swift-version 6 \
|
|
// RUN: -module-name Lib %t/Lib.swift -emit-module-path %t/Lib.swiftmodule
|
|
// RUN: %target-swift-frontend -emit-sil -O -swift-version 6 -I %t -module-name Client \
|
|
// RUN: %t/Client.swift | %FileCheck %s -check-prefix=EXHAUSTIVE
|
|
|
|
//--- Lib.swift
|
|
|
|
public enum NoCases: Error {}
|
|
|
|
public func mightThrow<R>(_ body: () throws(NoCases) -> R) throws(NoCases) -> R {
|
|
try body()
|
|
}
|
|
|
|
//--- Client.swift
|
|
|
|
import Lib
|
|
|
|
// RESILIENT-LABEL: sil @$s6Client4callSiy3Lib7NoCasesOYKF :
|
|
// RESILIENT: try_apply
|
|
// RESILIENT: } // end sil function '$s6Client4callSiy3Lib7NoCasesOYKF'
|
|
|
|
// EXHAUSTIVE-LABEL: sil @$s6Client4callSiy3Lib7NoCasesOYKF :
|
|
// EXHAUSTIVE: apply [nothrow]
|
|
// EXHAUSTIVE-NOT: try_apply
|
|
// EXHAUSTIVE: } // end sil function '$s6Client4callSiy3Lib7NoCasesOYKF'
|
|
public func call() throws(NoCases) -> Int {
|
|
try mightThrow { 42 }
|
|
}
|