// RUN: rm -rf %t // RUN: mkdir -p %t // RUN: %target-build-swift -Xfrontend -enable-experimental-property-behaviors %s -o %t/a.out // RUN: %target-run %t/a.out // REQUIRES: executable_test // REQUIRES: rdar24874073 import StdlibUnittest protocol delayedImmutable { associatedtype Value var storage: Value? { get set } } extension delayedImmutable { var value: Value { // The property can only be read after it's been initialized. get { guard let theValue = storage else { fatalError("delayedImmutable property read before initialization") } return theValue } // The property can only be written once to initialize it. set { guard storage == nil else { fatalError("delayedImmutable property rewritten after initialization") } storage = newValue } } static func initStorage() -> Value? { return nil } } protocol lazy { associatedtype Value var storage: Value? { get set } func parameter() -> Value } extension lazy { var value: Value { mutating get { if let existing = storage { return existing } let value = parameter() storage = value return value } set { storage = newValue } } static func initStorage() -> Value? { return nil } } var lazyEvaluated = false func evaluateLazy() -> Int { lazyEvaluated = true return 1738 } class Foo { var x: Int __behavior delayedImmutable var y: Int __behavior lazy { evaluateLazy() } } var DelayedImmutable = TestSuite("DelayedImmutable") DelayedImmutable.test("correct usage") { let foo = Foo() foo.x = 679 expectEqual(foo.x, 679) } DelayedImmutable.test("read before initialization") { let foo = Foo() expectCrashLater() _ = foo.x } DelayedImmutable.test("write after initialization") { let foo = Foo() foo.x = 679 expectCrashLater() foo.x = 680 } var Lazy = TestSuite("Lazy") Lazy.test("usage") { let foo = Foo() expectFalse(lazyEvaluated) expectEqual(foo.y, 1738) expectTrue(lazyEvaluated) lazyEvaluated = false expectEqual(foo.y, 1738) expectFalse(lazyEvaluated) foo.y = 36 expectEqual(foo.y, 36) expectFalse(lazyEvaluated) let foo2 = Foo() expectFalse(lazyEvaluated) foo2.y = 36 expectEqual(foo2.y, 36) expectFalse(lazyEvaluated) let foo3 = Foo() expectFalse(lazyEvaluated) expectEqual(foo3.y, 1738) expectTrue(lazyEvaluated) } runAllTests()