Files
swift-mirror/test/Interpreter/init_accessors.swift
Pavel Yaskevich 416bbaec8d [TypeChecker] InitAccessors: Fix handling of defaultable init accessor properties during default init synthesis
Default initializable init properties shouldn't prevent default
init synthesis and such properties without anything to initialize
should be considered by it.
2023-08-21 09:05:26 -07:00

850 lines
17 KiB
Swift

// RUN: %target-run-simple-swift | %FileCheck %s
// RUN: %target-run-simple-swift(-O) | %FileCheck %s
// REQUIRES: executable_test
struct TestInit {
var x: Int
var y: Int
var full: (Int, Int)
var point: (Int, Int) {
@storageRestrictions(initializes: y, full, accesses: x)
init(initialValue) {
self.y = initialValue.1
self.full = (self.x, self.y)
}
get { full }
set { full = newValue }
}
init(x: Int, y: Int) {
self.x = x
self.point = (x, y)
}
}
do {
let test = TestInit(x: 0, y: -1)
print("test-init: \(test.point)")
// CHECK: test-init: (0, -1)
}
struct TestSetter {
var x: Int
var y: Int
var point: (Int, Int) {
@storageRestrictions(accesses: x, y)
init(initialValue) {
}
get { (x, y) }
set { }
}
init(x: Int, y: Int) {
self.x = x
self.y = y
self.point = (x, y)
}
}
do {
let test = TestSetter(x: 0, y: -2)
print("test-setter: \(test.point)")
// CHECK: test-setter: (0, -2)
}
struct TestInitThenSetter {
var x: Int
var y: Int
var point: (Int, Int) {
@storageRestrictions(initializes: x, y)
init(initialValue) {
self.x = initialValue.0
self.y = initialValue.1
}
get { (x, y) }
set {
x = newValue.0
y = newValue.1
}
}
init(x: Int, y: Int) {
self.point = (x, y)
if x == 1 {
self.point = (0, 0)
}
}
}
do {
let test = TestInitThenSetter(x: 1, y: 2)
print("test-init-then-setter: \(test.point)")
// CHECK: test-init-then-setter: (0, 0)
}
struct TestPartialInt {
var x: Int
var y: Int
var pointX: Int {
@storageRestrictions(initializes: x)
init(newValue) {
self.x = newValue
}
get { x }
set { self.x = newValue }
}
var pointY: Int {
@storageRestrictions(initializes: y)
init(newValue) {
self.y = newValue
}
get { y }
set { self.y = newValue }
}
init(x: Int, y: Int) {
// Init
self.pointX = x
// Init
self.pointY = y
// Setter
self.pointX = 1
// Setter
self.pointY = 2
}
}
do {
let test = TestPartialInt(x: 0, y: -1)
print("test-partial-init: (\(test.pointX), \(test.pointY))")
// CHECK: test-partial-init: (1, 2)
}
struct TestNoInitAndInit {
var x: Int
var y: Int
var pointX: Int {
@storageRestrictions(accesses: x)
init(initalValue) {
}
get { x }
set { }
}
var pointY: Int {
@storageRestrictions(initializes: y)
init(initialValue) {
self.y = initialValue
}
get { y }
set { }
}
init(x: Int, y: Int) {
self.x = x
self.pointX = x
self.pointY = y
print("TestNoInitAndInit(x: \(self.x), y: \(self.y))")
}
}
do {
_ = TestNoInitAndInit(x: 10, y: -10)
// CHECK: TestNoInitAndInit(x: 10, y: -10)
}
class TestClass {
var x: Int
var y: (Int, [String])
var data: (Int, (Int, [String])) {
@storageRestrictions(initializes: x, y)
init(initialValue) {
x = initialValue.0
y = initialValue.1
}
get { (x, y) }
set {
x = newValue.0
y = newValue.1
}
}
init(x: Int, y: (Int, [String])) {
self.data = (x, y)
}
}
do {
let test = TestClass(x: 20, y: (0, ["a", "b"]))
print("test-class: \(test.data)")
// CHECK: test-class: (20, (0, ["a", "b"]))
}
struct TestGeneric<T, U> {
var a: T
var b: T
var c: U
var data: (T, T) {
@storageRestrictions(initializes: a, b, accesses: c)
init(initialValue) {
a = initialValue.0
b = initialValue.1
print("TestGeneric(c: \(c))")
}
get { (a, b) }
set { }
}
init(a: T, b: T, c: U) {
self.c = c
self.data = (a, b)
self.data = (b, a)
}
}
do {
let test = TestGeneric(a: 42, b: 0, c: [42, "a"] as [Any])
print("test-generic: data = \(test.data)")
// CHECK: TestGeneric(c: [42, "a"])
// CHECK-NEXT: test-generic: data = (42, 0)
}
func test_local_with_memberwise() {
class MyValue {}
struct TestMemberwiseConcrete {
var a: Int
var b: String
var pair: (Int, String) {
@storageRestrictions(initializes: a, b)
init(initialValue) {
a = initialValue.0
b = initialValue.1
}
get { (a, b) }
set { }
}
var c: [MyValue]
}
let concrete = TestMemberwiseConcrete(pair: (0, "a"), c: [])
print(concrete)
struct TestMemberwiseGeneric<T, C> where C: RangeReplaceableCollection, C.Element == T {
var _a: T
var _b: String
var _c: C
var a: T {
@storageRestrictions(initializes: _a)
init(initialValue) {
_a = initialValue
}
get { _a }
set { }
}
var pair: (String, C) {
@storageRestrictions(initializes: _b, _c, accesses: _a)
init(initialValue) {
_b = initialValue.0
_c = initialValue.1
_c.append(_a)
}
get { (_b, _c) }
set { }
}
}
let generic = TestMemberwiseGeneric(a: 1, pair: ("a", [0]))
print(generic)
}
test_local_with_memberwise()
// CHECK: TestMemberwiseConcrete(a: 0, b: "a", c: [])
// CHECK-NEXT: TestMemberwiseGeneric<Int, Array<Int>>(_a: 1, _b: "a", _c: [0, 1])
func test_assignments() {
struct Test {
var _a: Int
var _b: Int
var a: Int {
@storageRestrictions(initializes: _a)
init(initialValue) {
self._a = initialValue
print("a-init-accessor: \(self._a)")
}
get { _a }
set { _a = newValue + 1 }
}
var pair: (Int, Int) {
@storageRestrictions(initializes: _a, _b)
init(initialValue) {
_a = initialValue.0
_b = initialValue.1
}
get { (_a, _b) }
set { }
}
init(a: Int) {
// init
self.a = a
// re-assignment
self.a = a + 1
self._b = 42
// set
self.a = a + 2
}
init(a: Int, b: Int) {
self.a = a
self.pair = (0, b)
}
}
let test1 = Test(a: 0)
print("test-assignments-1: \(test1.pair)")
let test2 = Test(a: 0, b: 2)
print("test-assignments-2: \(test2.pair)")
}
test_assignments()
// CHECK: a-init-accessor: 0
// CHECK-NEXT: a-init-accessor: 1
// CHECK-NEXT: test-assignments-1: (3, 42)
// CHECK-NEXT: a-init-accessor: 0
// CHECK-NEXT: test-assignments-2: (0, 2)
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 { }
}
}
let test1 = Test1(_b: 42, a: 0)
print("test-memberwise-ordering-1: \(test1)")
struct Test2 {
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
}
let test2 = Test2(pair: (-1, -2))
print("test-memberwise-ordering-2: \(test2)")
struct Test3 {
var _a: Int
var _b: Int
var pair: (Int, Int) {
@storageRestrictions(accesses: _a, _b)
init(initialValue) {
}
get { (_a, _b) }
set { }
}
var _c: Int
}
let test3 = Test3(_a: 1, _b: 2, pair: (1, 2), _c: 3)
print("test-memberwise-ordering-3: \(test3)")
}
test_memberwise_ordering()
// CHECK: test-memberwise-ordering-1: Test1(_a: 0, _b: 42)
// CHECK-NEXT: test-memberwise-ordering-2: Test2(_a: -1, _b: -2)
// CHECK-NEXT: test-memberwise-ordering-3: Test3(_a: 1, _b: 2, _c: 3)
func test_memberwise_with_default_args() {
struct TestWithoutDefault {
var _a: Int
var _b: Int
var pair: (Int, Int) = (-1, 42) {
@storageRestrictions(initializes: _a, _b)
init(initialValue) {
_a = initialValue.0
_b = initialValue.1
}
get { (0, 42) }
set { }
}
}
let test1 = TestWithoutDefault()
print("test-memberwise_with_default-1: \(test1)")
let test2 = TestWithoutDefault(pair: (42, -1))
print("test-memberwise_with_default-2: \(test2)")
struct TestDefaulted {
var _a: Int = 0
var _b: Int = 0
var pair: (Int, Int) = (1, 2) {
@storageRestrictions(initializes: _a, _b)
init(initialValue) {
_a = initialValue.0
_b = initialValue.1
}
get { (_a, _b) }
set { }
}
}
let test3 = TestDefaulted()
print("test-defaulted-1: \(test3)")
let test4 = TestDefaulted(pair: (3, 4))
print("test-defaulted-2: \(test4)")
class TestClass {
var _q: String = "<<default>>"
var _a: Int = 1
var pair: (String, Int) = ("", 42) {
@storageRestrictions(initializes: _q, _a)
init(initialValue) {
_q = initialValue.0
_a = initialValue.1
}
get { (_q, _a) }
set { }
}
}
let test5 = TestClass()
print("test-defaulted-class: \(test5.pair)")
}
test_memberwise_with_default_args()
// CHECK: test-memberwise_with_default-1: TestWithoutDefault(_a: -1, _b: 42)
// CHECK-NEXT: test-memberwise_with_default-2: TestWithoutDefault(_a: 42, _b: -1)
// CHECK-NEXT: test-defaulted-1: TestDefaulted(_a: 1, _b: 2)
// CHECK-NEXT: test-defaulted-2: TestDefaulted(_a: 3, _b: 4)
// CHECK-NEXT: test-defaulted-class: ("", 42)
func test_init_accessors_without_setters() {
struct TestStruct<T> {
var _x: T
var x: T {
@storageRestrictions(initializes: _x)
init(initialValue) {
_x = initialValue
}
get { _x }
}
init(value: T) {
x = value
}
}
let test1 = TestStruct(value: 42)
print("test-without-setter1: \(test1.x)")
class Base<T: Collection> {
private var _v: T
var data: T {
@storageRestrictions(initializes: _v)
init(initialValue) {
_v = initialValue
}
get { _v }
}
init(data: T) {
self.data = data
}
}
let test2 = Base(data: [1, 2, 3])
print("test-without-setter2: \(test2.data)")
class Sub<U> : Base<U> where U: Collection, U.Element == String {
init(other: U) {
super.init(data: other)
}
}
let test3 = Sub(other: ["a", "b", "c"])
print("test-without-setter3: \(test3.data)")
}
test_init_accessors_without_setters()
// CHECK: test-without-setter1: 42
// CHECK-NEXT: test-without-setter2: [1, 2, 3]
// CHECK-NEXT: test-without-setter3: ["a", "b", "c"]
func test_effects_are_still_supported() {
struct Test {
var _a: Int
var _b: Int
var a: Int {
@storageRestrictions(initializes: _a, accesses: _b)
init(initialValue) {
_a = initialValue
_b = 0
}
get { _a }
}
}
let test = Test(_b: 1, a: 42)
print("effects-support-test: \(test)")
}
test_effects_are_still_supported()
// CHEKC: effects-support-test: Test(_a: 42, b: 0)
func test_memberwise_without_stored_properties() {
struct Test {
var a: Int {
init {
print("no-stored: a = \(newValue)")
}
get { 0 }
}
var b: Int {
init {
print("no-stored: b = \(newValue)")
}
get { 1 }
}
}
_ = Test(a: 1, b: 2)
}
test_memberwise_without_stored_properties()
// CHECK: no-stored: a = 1
// CHECK-NEXT: no-stored: b = 2
protocol P {
static var initialValue: Self { get }
}
func test_properties_with_inits() {
struct S: P, CustomStringConvertible {
var x: Int
static var initialValue: S { S(x: 42) }
var description: String {
"S(x: \(x))"
}
}
final class K: P, CustomStringConvertible {
var v: [String]
static var initialValue: K { K(v: ["question"]) }
var description: String {
"K(v: \(v))"
}
init(v: [String]) {
self.v = v
}
}
class Test<T: P> {
var _x: T
var x: T = T.initialValue {
@storageRestrictions(initializes: _x)
init {
_x = newValue
}
get { _x }
set { _x = newValue }
}
init() {}
}
print("test-init-expr-1: \(Test<S>().x)")
struct TestPair<T: P, U: P> {
var _data: (T, U)
var data: (T, U) = (T.initialValue, U.initialValue) {
@storageRestrictions(initializes: _data)
init(initialValue) {
_data = initialValue
}
get { _data }
set { _data = newValue }
}
init() {
}
init(x: T, y: U) {
self.data = (x, y)
}
}
print("test-init-expr-2: \(TestPair<S, K>().data)")
print("test-init-expr-2: \(TestPair<S, K>(x: S(x: 0), y: K(v: ["a", "b", "c"])).data)")
struct TestAssign<T: P> {
var _x: T
var x: T = T.initialValue {
@storageRestrictions(initializes: _x)
init {
_x = newValue
print("TestAssign in x.init: self.x = \(_x)")
}
get { _x }
set { _x = newValue }
}
var y: Int
init(x1: T, x2: T, y: Int) {
self.x = x1
self.y = y
self.x = x2
print("TestAssign: self.x = \(self.x)")
}
}
_ = TestAssign(x1: S(x: 0), x2: S(x: -3), y: 2)
class TestDefault : CustomStringConvertible {
var _a: Int
var a: Int = 42 {
@storageRestrictions(initializes: _a)
init {
_a = newValue
}
get { _a }
}
var b: String = "<<default>>"
var description: String {
"TestDefault(a: \(a), b: \(b))"
}
}
print("test-init-expr-3: \(TestDefault())")
}
test_properties_with_inits()
// CHECK: test-init-expr-1: S(x: 42)
// CHECK-NEXT: test-init-expr-2: (S(x: 42), K(v: ["question"]))
// CHECK-NEXT: test-init-expr-2: (S(x: 0), K(v: ["a", "b", "c"]))
// CHECK-NEXT: TestAssign in x.init: self.x = S(x: 42)
// CHECK-NEXT: TestAssign in x.init: self.x = S(x: 0)
// CHECK-NEXT: TestAssign: self.x = S(x: -3)
// CHECK-NEXT: test-init-expr-3: TestDefault(a: 42, b: <<default>>)
func test_inheritance() {
class Entity {
var _age: Int = 0
var age: Int = 0 {
@storageRestrictions(initializes: _age)
init { _age = newValue }
get { _age }
set { _age = newValue }
}
}
class Person : Entity, CustomStringConvertible {
var _firstName: String
var firstName: String = "<<unknown>>" {
@storageRestrictions(initializes: _firstName)
init { _firstName = newValue }
get { _firstName }
set { _firstName = newValue }
}
var description: String {
"Person(firstName: \(firstName), age: \(age))"
}
override init() {}
init(firstName: String, age: Int) {
super.init()
self.firstName = firstName
self.age = age
}
}
print("test-inheritance-1: \(Person())")
print("test-inheritance-2: \(Person(firstName: "Q", age: 42))")
}
test_inheritance()
// CHECK: test-inheritance-1: Person(firstName: <<unknown>>, age: 0)
// CHECK-NEXT: test-inheritance-2: Person(firstName: Q, age: 42)
do {
class BackingData<T> {
var data: [PartialKeyPath<T>: Any] = [:]
func get<V>(_ key: KeyPath<T, V>) -> V { data[key] as! V }
func set<V>(_ key: KeyPath<T, V>, _ value: V) {
data[key] = value
}
}
class Person : CustomStringConvertible {
var description: String {
"Person(name: \(name))"
}
private var backingData: BackingData<Person> = BackingData()
private var _name: Int
var name: String {
@storageRestrictions(accesses: backingData, initializes: _name)
init(newValue) {
self.backingData.set(\.name, newValue)
self._name = 0
}
get { self.backingData.get(\.name) }
set { self.backingData.set(\.name, newValue) }
}
init(name: String) {
self.name = name
}
init(backingData: BackingData<Person>) {
self.backingData = backingData
self._name = 0
}
}
let person = Person(name: "P")
print(person)
let localData = BackingData<Person>()
localData.set(\.name, "O")
print(Person(backingData: localData))
}
// CHECK: Person(name: P)
// CHECK-NEXT: Person(name: O)
do {
struct TestDefaultInitializable : CustomStringConvertible {
var description: String {
"TestDefaultInitializable(a: \(a))"
}
var _a: Int?
var a: Int? {
@storageRestrictions(initializes: _a)
init { _a = newValue }
get { _a }
}
}
print(TestDefaultInitializable())
print(TestDefaultInitializable(a: 42))
struct TestMixedDefaultInitalizable : CustomStringConvertible {
var description: String {
"TestMixedDefaultInitalizable(a: \(a), b: \(b))"
}
var a: Int? {
init {}
get { nil }
}
var _b: String
var b: String? {
@storageRestrictions(initializes: _b)
init { self._b = (newValue ?? "") }
get { _b }
set { _b = newValue ?? "" }
}
}
print(TestMixedDefaultInitalizable())
print(TestMixedDefaultInitalizable(b: "Hello"))
print(TestMixedDefaultInitalizable(a: 42))
}
// CHECK: TestDefaultInitializable(a: nil)
// CHECK-NEXT: TestDefaultInitializable(a: Optional(42))
// CHECK-NEXT: TestMixedDefaultInitalizable(a: nil, b: Optional(""))
// CHECK-NEXT: TestMixedDefaultInitalizable(a: nil, b: Optional("Hello"))
// CHECK-NEXT: TestMixedDefaultInitalizable(a: nil, b: Optional(""))