Files
swift-mirror/test/decl/subscript/addressors.swift
John McCall 7a4aeed570 Implement generalized accessors using yield-once coroutines.
For now, the accessors have been underscored as `_read` and `_modify`.
I'll prepare an evolution proposal for this feature which should allow
us to remove the underscores or, y'know, rename them to `purple` and
`lettuce`.

`_read` accessors do not make any effort yet to avoid copying the
value being yielded.  I'll work on it in follow-up patches.

Opaque accesses to properties and subscripts defined with `_modify`
accessors will use an inefficient `materializeForSet` pattern that
materializes the value to a temporary instead of accessing it in-place.
That will be fixed by migrating to `modify` over `materializeForSet`,
which is next up after the `read` optimizations.

SIL ownership verification doesn't pass yet for the test cases here
because of a general fault in SILGen where borrows can outlive their
borrowed value due to being cleaned up on the general cleanup stack
when the borrowed value is cleaned up on the formal-access stack.
Michael, Andy, and I discussed various ways to fix this, but it seems
clear to me that it's not in any way specific to coroutine accesses.

rdar://35399664
2018-07-23 18:59:58 -04:00

230 lines
7.1 KiB
Swift

// RUN: %target-typecheck-verify-swift -parse-stdlib
import Swift
func someValidAddress<T>() -> UnsafeMutablePointer<T> { fatalError() }
func someValidAddress<T>() -> UnsafePointer<T> { fatalError() }
struct ValidImmutable {
var base: UnsafePointer<Int>
subscript(index: Int) -> Int {
unsafeAddress {
return base
}
}
}
struct ValidBoth {
var base: UnsafeMutablePointer<Int>
subscript(index: Int) -> Int {
unsafeAddress {
return UnsafePointer(base)
}
unsafeMutableAddress {
return base
}
}
}
struct OnlyMutable {
var base: UnsafeMutablePointer<Int>
subscript(index: Int) -> Int {
unsafeMutableAddress { // expected-error {{subscript with a mutable addressor must also have a getter, addressor, or 'read' accessor}}
return base
}
}
}
struct Repeated {
var base: UnsafeMutablePointer<Int>
subscript(index: Int) -> Int {
unsafeAddress { // expected-note {{previous definition}}
return UnsafePointer(base)
}
unsafeAddress { // expected-error {{subscript already has an addressor}}
return base // expected-error {{cannot convert return expression of type 'UnsafeMutablePointer<Int>' to return type 'UnsafePointer<Int>'}}
}
}
}
struct RepeatedMutable {
var base: UnsafeMutablePointer<Int>
subscript(index: Int) -> Int {
unsafeAddress {
return UnsafePointer(base)
}
unsafeMutableAddress { // expected-note {{previous definition}}
return base
}
unsafeMutableAddress { // expected-error {{subscript already has a mutable addressor}}
return base
}
}
}
struct AddressorAndGet {
var base: UnsafePointer<Int>
subscript(index: Int) -> Int {
unsafeAddress { // expected-error {{subscript cannot provide both an addressor and a getter}}
return base
}
get { // expected-note {{getter defined here}}
return base.get() // expected-error {{value of type 'UnsafePointer<Int>' has no member 'get'}}
}
}
}
struct AddressorAndSet {
var base: UnsafePointer<Int>
subscript(index: Int) -> Int {
unsafeAddress {
return base
}
set {
}
}
}
struct MutableAddressorAndGet {
var base: UnsafeMutablePointer<Int>
subscript(index: Int) -> Int {
unsafeMutableAddress {
return base
}
get {
return base.pointee
}
}
}
protocol HasImmutableSubscript {
subscript(index: Int) -> Int { get }
}
protocol HasMutableSubscript {
subscript(index: Int) -> Int { get set } // expected-note {{protocol requires}}
}
struct DisobedientImmutableAddressor: HasMutableSubscript { // expected-error {{does not conform}}
subscript(index: Int) -> Int { // expected-note {{candidate is not settable}}
unsafeAddress { return someValidAddress() }
}
}
struct ObedientImmutableAddressor: HasImmutableSubscript {
subscript(index: Int) -> Int {
unsafeAddress { return someValidAddress() }
}
}
struct ObedientMutableAddressor: HasMutableSubscript {
subscript(index: Int) -> Int {
unsafeAddress { return someValidAddress() }
unsafeMutableAddress { return someValidAddress() }
}
}
protocol HasMutatingImmutableSubscript {
subscript(index: Int) -> Int { mutating get }
}
protocol HasMutatingMutableSubscript {
subscript(index: Int) -> Int { mutating get set } // expected-note {{protocol requires}}
}
// We allow mutating accessor requirements to be implemented by non-mutating accessors.
struct DisobedientImmutableAddressor2: HasMutatingMutableSubscript { // expected-error {{does not conform}}
subscript(index: Int) -> Int { // expected-note {{candidate is not settable}}
unsafeAddress { return someValidAddress() }
}
}
struct ObedientImmutableAddressor2: HasMutatingImmutableSubscript {
subscript(index: Int) -> Int {
unsafeAddress { return someValidAddress() }
}
}
struct ObedientMutableAddressor2: HasMutatingMutableSubscript {
subscript(index: Int) -> Int {
unsafeAddress { return someValidAddress() }
unsafeMutableAddress { return someValidAddress() }
}
}
// Non-mutating accessor requirements cannot be implemented by mutating accessors.
protocol HasNonMutatingMutableSubscript {
subscript(index: Int) -> Int { get nonmutating set } // expected-note {{protocol requires}}
}
struct DisobedientNonMutatingMutableAddressor: HasNonMutatingMutableSubscript { // expected-error {{does not conform}}
subscript(index: Int) -> Int {
unsafeAddress { return someValidAddress() }
unsafeMutableAddress { return someValidAddress() } // expected-note {{candidate is marked 'mutating' but protocol does not allow it}}
}
}
struct ObedientNonMutatingMutableAddressor: HasNonMutatingMutableSubscript {
subscript(index: Int) -> Int {
unsafeAddress { return someValidAddress() }
nonmutating unsafeMutableAddress { return someValidAddress() }
}
}
// FIXME: Actually plumb the work to fix the grammar in these
// diagnostics if/when we productize them. ("a addressor")
struct RedundantAddressors1 {
var owner : Builtin.NativeObject
subscript(index: Int) -> Int {
unsafeAddress { return someValidAddress() } // expected-note {{previous definition of addressor here}}
addressWithNativeOwner { return (someValidAddress(), owner) } // expected-error {{subscript already has an addressor}}
}
}
struct RedundantAddressors2 {
var owner : Builtin.NativeObject
subscript(index: Int) -> Int {
unsafeAddress { return someValidAddress() } // expected-note {{previous definition of addressor here}}
addressWithPinnedNativeOwner { return (someValidAddress(), owner) } // expected-error {{subscript already has an addressor}}
}
}
struct RedundantAddressors3 {
var owner : Builtin.NativeObject
subscript(index: Int) -> Int {
addressWithNativeOwner { return (someValidAddress(), owner) } // expected-note {{previous definition of addressor here}}
addressWithPinnedNativeOwner { return (someValidAddress(), owner) } // expected-error {{subscript already has an addressor}}
}
}
struct RedundantMutableAddressors1 {
var owner : Builtin.NativeObject
subscript(index: Int) -> Int {
unsafeAddress { return someValidAddress() }
unsafeMutableAddress { return someValidAddress() } // expected-note {{previous definition of mutable addressor here}}
mutableAddressWithNativeOwner { return (someValidAddress(), owner) } // expected-error {{subscript already has a mutable addressor}}
}
}
struct RedundantMutableAddressors2 {
var owner : Builtin.NativeObject
subscript(index: Int) -> Int {
unsafeAddress { return someValidAddress() }
unsafeMutableAddress { return someValidAddress() } // expected-note {{previous definition of mutable addressor here}}
mutableAddressWithNativeOwner { return (someValidAddress(), owner) } // expected-error {{subscript already has a mutable addressor}}
}
}
struct RedundantMutableAddressors3 {
var owner : Builtin.NativeObject
subscript(index: Int) -> Int {
unsafeAddress { return someValidAddress() }
unsafeMutableAddress { return someValidAddress() } // expected-note {{previous definition of mutable addressor here}}
mutableAddressWithNativeOwner { return (someValidAddress(), owner) } // expected-error {{subscript already has a mutable addressor}}
}
}