mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
709 lines
16 KiB
Swift
709 lines
16 KiB
Swift
// RUN: %target-typecheck-verify-swift
|
|
|
|
func test_empty_init_accessor() {
|
|
struct Test {
|
|
var empty: Int {
|
|
init { // Ok
|
|
}
|
|
|
|
get { 42 }
|
|
set { }
|
|
}
|
|
|
|
var noArgs: Int {
|
|
init(initialValue) { // Ok
|
|
}
|
|
|
|
get { 42 }
|
|
set { }
|
|
}
|
|
}
|
|
}
|
|
|
|
func test_invalid_init_accessor_use() {
|
|
var other: String = "" // expected-warning {{}}
|
|
var x: Int {
|
|
@storageRestrictions(initializes: other)
|
|
init(initialValue) {}
|
|
// expected-error@-1 {{init accessors could only be associated with properties}}
|
|
|
|
get { 42 }
|
|
}
|
|
|
|
struct X {
|
|
subscript(x: Int) -> Bool {
|
|
init(initialValue) {} // expected-error {{init accessors could only be associated with properties}}
|
|
|
|
get { false }
|
|
}
|
|
}
|
|
}
|
|
|
|
func test_use_of_initializes_accesses_on_non_inits() {
|
|
struct Test1 {
|
|
var x: Int
|
|
var y: String
|
|
|
|
var _x: Int {
|
|
@storageRestrictions(initializes: x, accesses: y)
|
|
init(initialValue) { // Ok
|
|
}
|
|
|
|
get { x }
|
|
set { }
|
|
}
|
|
|
|
var _y: String {
|
|
get { y }
|
|
|
|
@storageRestrictions(initializes: y)
|
|
// expected-error@-1 {{'@storageRestrictions' could only be used with init accessors}}
|
|
set(initialValue) {}
|
|
}
|
|
|
|
var _q: String {
|
|
get { y }
|
|
@storageRestrictions(accesses: x)
|
|
// expected-error@-1 {{'@storageRestrictions' could only be used with init accessors}}
|
|
set(initialValue) {}
|
|
}
|
|
|
|
init(x: Int, y: String) {
|
|
self.y = y
|
|
self._x = x
|
|
}
|
|
}
|
|
}
|
|
|
|
func test_invalid_refs_in_init_attrs() {
|
|
struct Test {
|
|
var c: Int { get { 42 } }
|
|
var x: Int {
|
|
@storageRestrictions(initializes: a, accesses: b, c)
|
|
// expected-error@-1 {{find type 'a' in scope}}
|
|
// expected-error@-2 {{find type 'b' in scope}}
|
|
// expected-error@-3 {{init accessor cannot refer to property 'c'; init accessors can refer only to stored properties}}
|
|
init(initialValue) {}
|
|
|
|
get { 0 }
|
|
}
|
|
|
|
var y: String {
|
|
@storageRestrictions(initializes: test)
|
|
// expected-error@-1 {{ambiguous reference to member 'test'}}
|
|
init(initialValue) {}
|
|
|
|
get { "" }
|
|
}
|
|
|
|
func test(_: Int) {} // expected-note {{'test' declared here}}
|
|
func test(_: String) -> Int { 42 } // expected-note {{'test' declared here}}
|
|
}
|
|
}
|
|
|
|
func test_assignment_to_let_properties() {
|
|
struct Test {
|
|
let x: Int
|
|
let y: Int // expected-note {{change 'let' to 'var' to make it mutable}}
|
|
|
|
var pointX: Int {
|
|
@storageRestrictions(initializes: x, accesses: y)
|
|
init(initialValue) {
|
|
self.x = initialValue // Ok
|
|
self.y = 42 // expected-error {{cannot assign to property: 'y' is a 'let' constant}}
|
|
}
|
|
|
|
get { x }
|
|
}
|
|
|
|
var point: (Int, Int) {
|
|
@storageRestrictions(initializes: x, y)
|
|
init(initialValue) {
|
|
self.x = initialValue.0 // Ok
|
|
self.y = initialValue.1 // Ok
|
|
}
|
|
|
|
get { (x, y) }
|
|
set { }
|
|
}
|
|
|
|
init(x: Int, y: Int) {
|
|
self.point = (x, y)
|
|
}
|
|
}
|
|
}
|
|
|
|
func test_duplicate_and_computed_lazy_properties() {
|
|
struct Test1 {
|
|
var _a: Int
|
|
var _b: Int
|
|
|
|
var a: Int {
|
|
@storageRestrictions(initializes: _b, _a, accesses: _a)
|
|
// expected-error@-1 {{property '_a' cannot be both initialized and accessed}}
|
|
init(initialValue) {
|
|
}
|
|
|
|
get { _a }
|
|
set { }
|
|
}
|
|
|
|
init() {
|
|
}
|
|
}
|
|
|
|
struct Test2 {
|
|
var _a: Int
|
|
|
|
var a: Int {
|
|
@storageRestrictions(initializes: a, c, accesses: _a, b)
|
|
// expected-error@-1 {{init accessor cannot refer to property 'a'; init accessors can refer only to stored properties}}
|
|
// expected-error@-2 {{init accessor cannot refer to property 'b'; init accessors can refer only to stored properties}}
|
|
// expected-error@-3 {{init accessor cannot refer to property 'c'; init accessors can refer only to stored properties}}
|
|
init(initialValue) {}
|
|
|
|
get { _a }
|
|
}
|
|
|
|
var b: Int {
|
|
get { 42 }
|
|
}
|
|
|
|
lazy var c: Int = 42
|
|
}
|
|
}
|
|
|
|
func test_invalid_self_uses() {
|
|
func capture<T>(_: T) -> Int? { nil }
|
|
|
|
struct Test {
|
|
var a: Int {
|
|
init(initialValue) {
|
|
let x = self
|
|
// expected-error@-1 {{'self' within init accessors can only be used to reference properties listed in 'initializes' and 'accesses'; init accessors are run before 'self' is fully available}}
|
|
|
|
_ = {
|
|
print(self)
|
|
// expected-error@-1 {{'self' within init accessors can only be used to reference properties listed in 'initializes' and 'accesses'; init accessors are run before 'self' is fully available}}
|
|
}
|
|
|
|
_ = { [weak self] in
|
|
// expected-error@-1 {{'self' within init accessors can only be used to reference properties listed in 'initializes' and 'accesses'; init accessors are run before 'self' is fully available}}
|
|
}
|
|
|
|
_ = {
|
|
guard let _ = capture(self) else {
|
|
// expected-error@-1 {{'self' within init accessors can only be used to reference properties listed in 'initializes' and 'accesses'; init accessors are run before 'self' is fully available}}
|
|
return
|
|
}
|
|
}
|
|
|
|
Test.test(self)
|
|
// expected-error@-1 {{'self' within init accessors can only be used to reference properties listed in 'initializes' and 'accesses'; init accessors are run before 'self' is fully available}}
|
|
}
|
|
|
|
get { 42 }
|
|
set { }
|
|
}
|
|
|
|
static func test<T>(_: T) {}
|
|
}
|
|
}
|
|
|
|
func test_invalid_references() {
|
|
struct Test {
|
|
var _a: Int
|
|
var _b: Int
|
|
|
|
var c: String
|
|
static var c: String = ""
|
|
|
|
var _d: String
|
|
|
|
var data: Int {
|
|
@storageRestrictions(initializes: _a, accesses: _d)
|
|
init(initialValue) {
|
|
_a = initialValue // Ok
|
|
|
|
print(_d) // Ok
|
|
self._d = "" // Ok
|
|
|
|
if self._b > 0 { // expected-error {{cannot reference instance member '_b'; init accessors can only refer to instance properties listed in 'initializes' and 'accesses' attributes}}
|
|
}
|
|
|
|
let x = c.lowercased()
|
|
// expected-error@-1 {{static member 'c' cannot be used on instance of type 'Test'}}
|
|
|
|
print(Test.c.lowercased()) // Ok
|
|
|
|
guard let v = test() else {
|
|
// expected-error@-1 {{cannot reference instance member 'test'; init accessors can only refer to instance properties listed in 'initializes' and 'accesses' attributes}}
|
|
return
|
|
}
|
|
|
|
_ = {
|
|
if true {
|
|
print(_b)
|
|
// expected-error@-1 {{cannot reference instance member '_b'; init accessors can only refer to instance properties listed in 'initializes' and 'accesses' attributes}}
|
|
print(self._b)
|
|
// expected-error@-1 {{cannot reference instance member '_b'; init accessors can only refer to instance properties listed in 'initializes' and 'accesses' attributes}}
|
|
}
|
|
}
|
|
}
|
|
|
|
get { _a }
|
|
set { }
|
|
}
|
|
|
|
func test() -> Int? { 42 }
|
|
|
|
init() {}
|
|
}
|
|
}
|
|
|
|
func test_memberwise_with_overlaps_dont_synthesize_inits() {
|
|
struct Test1<T, U> {
|
|
var _a: T
|
|
var _b: Int
|
|
|
|
var a: T {
|
|
@storageRestrictions(initializes: _a)
|
|
init(initialValue) {
|
|
_a = initialValue
|
|
}
|
|
|
|
get { _a }
|
|
set { }
|
|
}
|
|
|
|
var pair: (T, Int) {
|
|
@storageRestrictions(initializes: _a, _b)
|
|
init(initialValue) {
|
|
_a = initialValue.0
|
|
_b = initialValue.1
|
|
}
|
|
|
|
get { (_a, _b) }
|
|
set { }
|
|
}
|
|
|
|
var c: U
|
|
}
|
|
|
|
_ = Test1<String, [Double]>(a: "a", pair: ("b", 1), c: [3.0])
|
|
// expected-error@-1 {{'Test1<String, [Double]>' cannot be constructed because it has no accessible initializers}}
|
|
|
|
struct Test2<T, U> {
|
|
var _a: T
|
|
var _b: Int
|
|
|
|
var a: T {
|
|
@storageRestrictions(initializes: _a)
|
|
init(initialValue) {
|
|
_a = initialValue
|
|
}
|
|
|
|
get { _a }
|
|
set { }
|
|
}
|
|
|
|
var b: Int {
|
|
@storageRestrictions(initializes: _b)
|
|
init(initialValue) {
|
|
_b = initialValue
|
|
}
|
|
|
|
get { _b }
|
|
set { }
|
|
}
|
|
|
|
var _c: U
|
|
|
|
var pair: (T, U) {
|
|
@storageRestrictions(initializes: _a, _c)
|
|
init(initialValue) {
|
|
_a = initialValue.0
|
|
_c = initialValue.1
|
|
}
|
|
|
|
get { (_a, _c) }
|
|
set { }
|
|
}
|
|
}
|
|
|
|
_ = Test2<String, Int>(a: "a", pair: ("c", 2), b: 0)
|
|
// expected-error@-1 {{'Test2<String, Int>' cannot be constructed because it has no accessible initializers}}
|
|
|
|
struct Test3<T, U> {
|
|
var _a: T
|
|
var _b: Int
|
|
|
|
var a: T {
|
|
@storageRestrictions(initializes: _a)
|
|
init(initialValue) {
|
|
_a = initialValue
|
|
}
|
|
|
|
get { _a }
|
|
set { }
|
|
}
|
|
|
|
var b: Int {
|
|
@storageRestrictions(initializes: _b)
|
|
init(initialValue) {
|
|
_b = initialValue
|
|
}
|
|
|
|
get { _b }
|
|
set { }
|
|
}
|
|
|
|
var _c: U
|
|
|
|
var c: U {
|
|
@storageRestrictions(initializes: _c)
|
|
init(initialValue) {
|
|
_c = initialValue
|
|
}
|
|
|
|
get { _c }
|
|
set { }
|
|
}
|
|
|
|
var triple: (T, Int, U) {
|
|
@storageRestrictions(initializes: _a, _b, _c)
|
|
init(initialValue) {
|
|
_a = initialValue.0
|
|
_b = initialValue.1
|
|
_c = initialValue.2
|
|
}
|
|
|
|
get { (_a, _b, _c) }
|
|
set { }
|
|
}
|
|
}
|
|
|
|
_ = Test3<String, [Double]>(a: "a", triple: ("b", 2, [1.0, 2.0]), b: 0, c: [1.0])
|
|
// expected-error@-1 {{'Test3<String, [Double]>' cannot be constructed because it has no accessible initializers}}
|
|
}
|
|
|
|
func test_memberwise_ordering() {
|
|
struct Test1 {
|
|
var _a: Int
|
|
var _b: Int
|
|
|
|
var a: Int {
|
|
@storageRestrictions(initializes: _a, accesses: _b)
|
|
init(initialValue) {
|
|
_a = initialValue
|
|
}
|
|
|
|
get { _a }
|
|
set { }
|
|
}
|
|
}
|
|
|
|
_ = Test1(_b: 42, a: 0) // Ok
|
|
|
|
struct Test2 { // expected-error {{cannot synthesize memberwise initializer}}
|
|
var _a: Int
|
|
|
|
var a: Int {
|
|
@storageRestrictions(initializes: _a, accesses: _b)
|
|
init(initialValue) {
|
|
// expected-note@-1 {{init accessor for 'a' cannot access stored property '_b' because it is called before '_b' is initialized}}
|
|
_a = initialValue
|
|
}
|
|
|
|
get { _a }
|
|
}
|
|
|
|
var _b: Int
|
|
}
|
|
|
|
struct Test3 {
|
|
var _a: Int
|
|
|
|
var pair: (Int, Int) {
|
|
@storageRestrictions(initializes: _a, _b)
|
|
init(initialValue) {
|
|
_a = initialValue.0
|
|
_b = initialValue.1
|
|
}
|
|
|
|
get { (_a, _b) }
|
|
set { }
|
|
}
|
|
|
|
var _b: Int
|
|
}
|
|
|
|
_ = Test3(pair: (0, 1)) // Ok
|
|
|
|
struct Test4 {
|
|
var _a: Int
|
|
var _b: Int
|
|
|
|
var pair: (Int, Int) {
|
|
@storageRestrictions(accesses: _a, _b)
|
|
init(initalValue) {
|
|
}
|
|
|
|
get { (_a, _b) }
|
|
set { }
|
|
}
|
|
|
|
var _c: Int
|
|
}
|
|
|
|
_ = Test4(_a: 0, _b: 1, pair: (1, 2), _c: 2) // Ok
|
|
|
|
struct Test5 {
|
|
var _a: Int
|
|
var _b: Int
|
|
|
|
var c: Int {
|
|
@storageRestrictions(initializes: _c, accesses: _a, _b)
|
|
init(initalValue) {
|
|
}
|
|
|
|
get { _c }
|
|
set { }
|
|
}
|
|
|
|
var _c: Int
|
|
}
|
|
|
|
_ = Test5(_a: 0, _b: 1, c: 2) // Ok
|
|
}
|
|
|
|
func test_default_arguments_are_analyzed() {
|
|
struct Test {
|
|
var pair: (Int, Int) = (0, 1) { // Ok
|
|
init {}
|
|
|
|
get { (0, 1) }
|
|
}
|
|
|
|
var other: (Int, String) = ("", 42) {
|
|
// expected-error@-1 {{cannot convert value of type '(String, Int)' to specified type '(Int, String)'}}
|
|
init(initialValue) {}
|
|
|
|
get { (0, "") }
|
|
}
|
|
|
|
var otherPair = (0, 1) {
|
|
// expected-error@-1 {{computed property must have an explicit type}}
|
|
init(initalValue) {}
|
|
|
|
get { 42 }
|
|
// expected-error@-1 {{cannot convert return expression of type 'Int' to return type '(Int, Int)'}}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct TestStructPropWithoutSetter {
|
|
var _x: Int
|
|
|
|
var x: Int {
|
|
@storageRestrictions(initializes: _x)
|
|
init(initialValue) {
|
|
self._x = initialValue
|
|
}
|
|
|
|
get { _x }
|
|
}
|
|
|
|
init(v: Int) {
|
|
x = v // Ok
|
|
}
|
|
}
|
|
|
|
extension TestStructPropWithoutSetter {
|
|
init(other: Int) {
|
|
x = other // Ok
|
|
}
|
|
|
|
init(other: inout TestStructPropWithoutSetter, v: Int) {
|
|
other.x = v // expected-error {{cannot assign to property: 'x' is immutable}}
|
|
}
|
|
}
|
|
|
|
do {
|
|
class TestClassPropWithoutSetter { // expected-error {{class 'TestClassPropWithoutSetter' has no initializers}}
|
|
var x: Int {
|
|
init {
|
|
}
|
|
|
|
get { 0 }
|
|
}
|
|
}
|
|
|
|
// This should generate only memberwise initializer because `a` doesn't have a default
|
|
struct TestStructWithoutSetter { // expected-note {{'init(a:)' declared here}}
|
|
var a: Int {
|
|
init {
|
|
}
|
|
get { 0 }
|
|
}
|
|
}
|
|
|
|
_ = TestStructWithoutSetter() // expected-error {{missing argument for parameter 'a' in call}}
|
|
_ = TestStructWithoutSetter(a: 42) // Ok
|
|
|
|
struct TestDefaultInitializable {
|
|
var a: Int? {
|
|
init {}
|
|
get { nil }
|
|
}
|
|
}
|
|
|
|
_ = TestDefaultInitializable() // Ok (`a` is initialized to `nil`)
|
|
|
|
struct TestMixedDefaultInitializable {
|
|
var a: Int? {
|
|
init {}
|
|
get { nil }
|
|
}
|
|
|
|
var _b: String
|
|
var b: String? {
|
|
@storageRestrictions(initializes: _b)
|
|
init { _b = newValue ?? "" }
|
|
get { _b }
|
|
set { _b = newValue ?? "" }
|
|
}
|
|
}
|
|
|
|
_ = TestMixedDefaultInitializable() // Ok (both `a` and `b` are initialized to `nil`)
|
|
|
|
class SubTestPropWithoutSetter : TestClassPropWithoutSetter {
|
|
init(otherV: Int) {
|
|
x = otherV // Ok
|
|
}
|
|
}
|
|
|
|
class OtherWithoutSetter<U> {
|
|
var data: U {
|
|
init {
|
|
}
|
|
|
|
get { fatalError() }
|
|
}
|
|
|
|
init(data: U) {
|
|
self.data = data // Ok
|
|
}
|
|
}
|
|
}
|
|
|
|
func test_invalid_storage_restrictions() {
|
|
struct Test {
|
|
var _a: Int = 0
|
|
var _b: Int = 0
|
|
|
|
var a: Int {
|
|
@storageRestrictions()
|
|
// expected-error@-1 {{missing label in '@storageRestrictions'}}
|
|
init {}
|
|
|
|
get { _a }
|
|
}
|
|
|
|
var b: Int {
|
|
@storageRestrictions(initializes:)
|
|
// expected-error@-1 {{expected property name in '@storageRestrictions' list}}
|
|
init {}
|
|
|
|
get { _b }
|
|
}
|
|
|
|
var c: Int {
|
|
@storageRestrictions(initializes: a, initializes: b)
|
|
// expected-error@-1 {{duplicate label 'initializes' in '@storageRestrictions'}}
|
|
// expected-error@-2 {{init accessor cannot refer to property 'a'; init accessors can refer only to stored properties}}
|
|
init {}
|
|
|
|
get { 0 }
|
|
}
|
|
|
|
var d: Int {
|
|
@storageRestrictions(accesses: a, accesses: c)
|
|
// expected-error@-1 {{duplicate label 'accesses' in '@storageRestrictions'}}
|
|
// expected-error@-2 {{init accessor cannot refer to property 'a'; init accessors can refer only to stored properties}}
|
|
init {}
|
|
|
|
get { 0 }
|
|
}
|
|
|
|
var e: Int {
|
|
@storageRestrictions(initialize: a, b, accesses: c, d)
|
|
// expected-error@-1 {{unexpected label 'initialize' in '@storageRestrictions'}}
|
|
init {}
|
|
|
|
get { 0 }
|
|
}
|
|
|
|
var f: Int {
|
|
@storageRestrictions(initializes: _a, accesses: _b, _a)
|
|
// expected-error@-1 {{property '_a' cannot be both initialized and accessed}}
|
|
init {}
|
|
// expected-error@-1 {{variable with an init accessor must also have a getter}}
|
|
}
|
|
|
|
var g: Int {
|
|
@storageRestrictions(initializes: _a)
|
|
// expected-error@-1 {{'@storageRestrictions' could only be used with init accessors}}
|
|
get { 0 }
|
|
}
|
|
|
|
init() {}
|
|
}
|
|
}
|
|
|
|
do {
|
|
struct Test1 {
|
|
var q: String
|
|
var a: Int? {
|
|
init {}
|
|
get { 42 }
|
|
}
|
|
}
|
|
|
|
_ = Test1(q: "some question") // Ok `a` is default initialized to `nil`
|
|
_ = Test1(q: "ultimate question", a: 42)
|
|
|
|
struct Test2 {
|
|
var q: String
|
|
|
|
var _a: Int?
|
|
var a: Int? {
|
|
@storageRestrictions(initializes: _a)
|
|
init {
|
|
_a = newValue
|
|
}
|
|
get { _a }
|
|
set { _a = newValue }
|
|
}
|
|
}
|
|
|
|
_ = Test2(q: "some question") // Ok `a` is default initialized to `nil`
|
|
_ = Test2(q: "ultimate question", a: 42)
|
|
}
|
|
|
|
struct Test2ForExtension {
|
|
var _x: Int
|
|
}
|
|
|
|
extension Test2ForExtension {
|
|
var extendedX: Int {
|
|
@storageRestrictions(initializes: _x)
|
|
init {
|
|
// expected-error@-1 {{init accessors cannot be declared in an extension}}
|
|
self._x = newValue
|
|
}
|
|
get { _x }
|
|
set { _x = newValue }
|
|
}
|
|
}
|