Files
swift-mirror/test/SILOptimizer/moveonly_discard.swift
Joe Groff 359e045192 Require switch on a noncopyable-type binding to be explicitly consume-d.
Pattern matching as currently implemented is consuming, but that's not
necessarily what we want to be the default behavior when borrowing pattern
matching is implemented. When a binding of noncopyable type is pattern-matched,
require it to be annotated with the `consume` operator explicitly. That way,
when we introduce borrowing pattern matching later, we have the option to make
`switch x` do the right thing without subtly changing the behavior of existing
code. rdar://110073984
2023-06-02 18:14:37 -07:00

98 lines
2.5 KiB
Swift

// RUN: %target-swift-frontend -sil-verify-all -verify -emit-sil -enable-experimental-feature MoveOnlyEnumDeinits %s
func posix_close(_ t: Int) {}
@_moveOnly
struct GoodFileDescriptor {
let _fd: Int = 0
var rawFileDescriptor: Int {
__consuming get {
let x = _fd
discard self
return x
}
}
__consuming func close() {
posix_close(_fd)
discard self
}
deinit { // expected-error {{'self' consumed more than once}}
// FIXME: this is suppose to be valid. rdar://106044273
close() // expected-note {{consumed here}}
} // expected-note {{consumed again here}}
}
@_moveOnly
struct BadFileDescriptor {
let _fd: Int = 0
deinit {}
var rawFileDescriptor: Int {
__consuming get { // expected-error {{'self' consumed more than once}}
discard self // expected-note {{consumed here}}
return self.rawFileDescriptor // expected-note {{consumed again here}}
// expected-warning@-1 {{function call causes an infinite recursion}}
}
}
__consuming func closeBoring(_ b: Bool) -> Int { // expected-error {{'self' consumed more than once}}
if b {
discard self // expected-note {{consumed here}}
}
return rawFileDescriptor // expected-note {{consumed again here}}
}
__consuming func closeRepeatedly(_ n: Int) -> Int { // expected-error {{'self' used after consume}}
for _ in 0..<n {
posix_close(_fd) // expected-note {{used here}}
discard self // expected-note {{consumed here}}
}
return 0
}
}
final class Wallet {
var ticket1: Ticket = .green
}
@_moveOnly enum Ticket {
case green
case yellow
case red
case pagedOut(GoodFileDescriptor)
case within(Wallet)
consuming func discard() { discard self }
init(inWallet wallet: Wallet? = nil) { // expected-error {{'self' consumed more than once}}
self = .within(Wallet())
if let existingWallet = wallet {
discard()
self = .within(existingWallet)
}
discard(forever: true) // expected-note {{consumed here}}
} // expected-note {{consumed again here}}
__consuming func discard(forever: Bool) { // expected-error {{'self' consumed in a loop}}
while forever {
discard self // expected-note {{consumed here}}
}
}
__consuming func inspect() { // expected-error {{'self' consumed more than once}}
switch consume self { // expected-note {{consumed here}}
case .green, .yellow, .red:
discard self // expected-note {{consumed again here}}
default:
return
}
}
deinit {}
}