Skip to content

Commit a3b4f53

Browse files
authored
Merge pull request #66499 from phausler/pr/observable_initializers_5_9
🍒[Observation] Add property definite initialization support
2 parents 4fd4f99 + 1156e6e commit a3b4f53

File tree

3 files changed

+43
-13
lines changed

3 files changed

+43
-13
lines changed

lib/Macros/Sources/ObservationMacros/ObservableMacro.swift

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -218,17 +218,15 @@ extension ObservableMacro: MemberMacro {
218218
declaration.addIfNeeded(ObservableMacro.registrarVariable(observableType), to: &declarations)
219219
declaration.addIfNeeded(ObservableMacro.accessFunction(observableType), to: &declarations)
220220
declaration.addIfNeeded(ObservableMacro.withMutationFunction(observableType), to: &declarations)
221-
221+
222+
#if !OBSERVATION_SUPPORTS_PEER_MACROS
222223
let storedInstanceVariables = declaration.definedVariables.filter { $0.isValidForObservation }
223224
for property in storedInstanceVariables {
224-
if property.hasMacroApplication(ObservableMacro.ignoredMacroName) { continue }
225-
if property.initializer == nil {
226-
context.addDiagnostics(from: DiagnosticsError(syntax: property, message: "@Observable requires property '\(property.identifier?.text ?? "")' to have an initial value", id: .missingInitializer), node: property)
227-
}
228-
let storage = DeclSyntax(property.privatePrefixed("_", addingAttribute: ObservableMacro.ignoredAttribute))
229-
declaration.addIfNeeded(storage, to: &declarations)
230-
225+
if property.hasMacroApplication(ObservableMacro.ignoredMacroName) { continue }
226+
let storage = DeclSyntax(property.privatePrefixed("_", addingAttribute: ObservableMacro.ignoredAttribute))
227+
declaration.addIfNeeded(storage, to: &declarations)
231228
}
229+
#endif
232230

233231
return declarations
234232
}
@@ -309,6 +307,13 @@ public struct ObservationTrackedMacro: AccessorMacro {
309307
return []
310308
}
311309

310+
let initAccessor: AccessorDeclSyntax =
311+
"""
312+
init(initialValue) initializes(_\(identifier)) {
313+
_\(identifier) = initialValue
314+
}
315+
"""
316+
312317
let getAccessor: AccessorDeclSyntax =
313318
"""
314319
get {
@@ -326,7 +331,7 @@ public struct ObservationTrackedMacro: AccessorMacro {
326331
}
327332
"""
328333

329-
return [getAccessor, setAccessor]
334+
return [initAccessor, getAccessor, setAccessor]
330335
}
331336
}
332337

@@ -343,8 +348,9 @@ extension ObservationTrackedMacro: PeerMacro {
343348
property.isValidForObservation else {
344349
return []
345350
}
346-
347-
if property.hasMacroApplication(ObservableMacro.ignoredMacroName) {
351+
352+
if property.hasMacroApplication(ObservableMacro.ignoredMacroName) ||
353+
property.hasMacroApplication(ObservableMacro.trackedMacroName) {
348354
return []
349355
}
350356

stdlib/public/Observation/Sources/Observation/Observable.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,21 @@
1616
#if $Macros && hasAttribute(attached)
1717

1818
@available(SwiftStdlib 5.9, *)
19+
#if OBSERVATION_SUPPORTS_PEER_MACROS
20+
@attached(member, names: named(_$observationRegistrar), named(access), named(withMutation))
21+
#else
1922
@attached(member, names: named(_$observationRegistrar), named(access), named(withMutation), arbitrary)
23+
#endif
2024
@attached(memberAttribute)
2125
@attached(conformance)
2226
public macro Observable() =
2327
#externalMacro(module: "ObservationMacros", type: "ObservableMacro")
2428

2529
@available(SwiftStdlib 5.9, *)
2630
@attached(accessor)
27-
// @attached(peer, names: prefixed(_))
31+
#if OBSERVATION_SUPPORTS_PEER_MACROS
32+
@attached(peer, names: prefixed(_))
33+
#endif
2834
public macro ObservationTracked() =
2935
#externalMacro(module: "ObservationMacros", type: "ObservationTrackedMacro")
3036

test/stdlib/Observation/Observable.swift

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// REQUIRES: swift_swift_parser, executable_test
22

3-
// RUN: %target-run-simple-swift( -Xfrontend -disable-availability-checking -parse-as-library -enable-experimental-feature Macros -Xfrontend -plugin-path -Xfrontend %swift-host-lib-dir/plugins)
3+
// RUN: %target-run-simple-swift( -Xfrontend -disable-availability-checking -parse-as-library -enable-experimental-feature InitAccessors -enable-experimental-feature Macros -Xfrontend -plugin-path -Xfrontend %swift-host-lib-dir/plugins)
44

55
// REQUIRES: observation
66
// REQUIRES: concurrency
@@ -21,6 +21,24 @@ struct Structure {
2121
var field: Int = 0
2222
}
2323

24+
@Observable
25+
struct MemberwiseInitializers {
26+
var field: Int
27+
}
28+
29+
func validateMemberwiseInitializers() {
30+
_ = MemberwiseInitializers(field: 3)
31+
}
32+
33+
@Observable
34+
struct DefiniteInitialization {
35+
var field: Int
36+
37+
init(field: Int) {
38+
self.field = field
39+
}
40+
}
41+
2442
@Observable
2543
class ContainsWeak {
2644
weak var obj: AnyObject? = nil

0 commit comments

Comments
 (0)