| // 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 |
| |
| import StdlibUnittest |
| |
| /// An immutable property with "delayed" initialization semantics. The property |
| /// may be set at most once, after which it is not allowed to be mutated. |
| /// The property must also be set before it is ever read. |
| 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 |
| } |
| } |
| |
| class Foo { |
| var x: Int __behavior delayedImmutable |
| } |
| |
| 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 |
| } |
| |
| runAllTests() |