Skip to content

Commit bfee8f6

Browse files
authored
Make all generated members nonisolated (#26)
* Make all generated members nonisolated * Add test coverage for main actor isolation
1 parent c7c829e commit bfee8f6

File tree

2 files changed

+57
-39
lines changed

2 files changed

+57
-39
lines changed

Sources/AnyLanguageModelMacros/GenerableMacro.swift

Lines changed: 30 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -73,16 +73,11 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
7373
extendedType: type,
7474
inheritanceClause: InheritanceClauseSyntax(
7575
inheritedTypes: InheritedTypeListSyntax([
76-
InheritedTypeSyntax(
77-
type: TypeSyntax("Generable")
78-
)
76+
InheritedTypeSyntax(type: TypeSyntax(stringLiteral: "Generable"))
7977
])
8078
),
81-
memberBlock: MemberBlockSyntax(
82-
members: MemberBlockItemListSyntax([])
83-
)
79+
memberBlock: MemberBlockSyntax(members: [])
8480
)
85-
8681
return [extensionDecl]
8782
}
8883

@@ -263,9 +258,9 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
263258
if properties.isEmpty {
264259
return DeclSyntax(
265260
stringLiteral: """
266-
public init(_ generatedContent: GeneratedContent) throws {
261+
nonisolated public init(_ generatedContent: GeneratedContent) throws {
267262
self._rawGeneratedContent = generatedContent
268-
263+
269264
guard case .structure = generatedContent.kind else {
270265
throw DecodingError.typeMismatch(
271266
\(structName).self,
@@ -278,16 +273,16 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
278273
} else {
279274
return DeclSyntax(
280275
stringLiteral: """
281-
public init(_ generatedContent: GeneratedContent) throws {
276+
nonisolated public init(_ generatedContent: GeneratedContent) throws {
282277
self._rawGeneratedContent = generatedContent
283-
278+
284279
guard case .structure(let properties, _) = generatedContent.kind else {
285280
throw DecodingError.typeMismatch(
286281
\(structName).self,
287282
DecodingError.Context(codingPath: [], debugDescription: "Expected structure for \(structName)")
288283
)
289284
}
290-
285+
291286
\(propertyExtractions)
292287
}
293288
"""
@@ -489,9 +484,9 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
489484
if properties.isEmpty {
490485
return DeclSyntax(
491486
stringLiteral: """
492-
public var generatedContent: GeneratedContent {
487+
nonisolated public var generatedContent: GeneratedContent {
493488
let properties: [String: GeneratedContent] = [:]
494-
489+
495490
return GeneratedContent(
496491
kind: .structure(
497492
properties: properties,
@@ -504,10 +499,10 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
504499
} else {
505500
return DeclSyntax(
506501
stringLiteral: """
507-
public var generatedContent: GeneratedContent {
502+
nonisolated public var generatedContent: GeneratedContent {
508503
var properties: [String: GeneratedContent] = [:]
509504
\(propertyConversions)
510-
505+
511506
return GeneratedContent(
512507
kind: .structure(
513508
properties: properties,
@@ -565,8 +560,7 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
565560

566561
return DeclSyntax(
567562
stringLiteral: """
568-
public static var generationSchema: GenerationSchema {
569-
563+
nonisolated public static var generationSchema: GenerationSchema {
570564
return GenerationSchema(
571565
type: Self.self,
572566
description: \(description.map { "\"\($0)\"" } ?? "\"Generated \(structName)\""),
@@ -580,7 +574,7 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
580574
private static func generateAsPartiallyGeneratedMethod(structName: String) -> DeclSyntax {
581575
return DeclSyntax(
582576
stringLiteral: """
583-
public func asPartiallyGenerated() -> PartiallyGenerated {
577+
nonisolated public func asPartiallyGenerated() -> PartiallyGenerated {
584578
return try! PartiallyGenerated(_rawGeneratedContent)
585579
}
586580
"""
@@ -590,7 +584,7 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
590584
private static func generateAsPartiallyGeneratedMethodForEnum(enumName: String) -> DeclSyntax {
591585
return DeclSyntax(
592586
stringLiteral: """
593-
public func asPartiallyGenerated() -> \(enumName) {
587+
nonisolated public func asPartiallyGenerated() -> \(enumName) {
594588
return self
595589
}
596590
"""
@@ -618,19 +612,19 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
618612
stringLiteral: """
619613
public struct PartiallyGenerated: Sendable, ConvertibleFromGeneratedContent {
620614
\(optionalProperties)
621-
615+
622616
private let rawContent: GeneratedContent
623-
617+
624618
public init(_ generatedContent: GeneratedContent) throws {
625619
self.rawContent = generatedContent
626-
620+
627621
if \(properties.isEmpty ? "case .structure = generatedContent.kind" : "case .structure(let properties, _) = generatedContent.kind") {
628622
\(propertyExtractions)
629623
} else {
630624
\(properties.map { "self.\($0.name) = nil" }.joined(separator: "\n "))
631625
}
632626
}
633-
627+
634628
public var generatedContent: GeneratedContent {
635629
return rawContent
636630
}
@@ -642,7 +636,7 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
642636
private static func generateInstructionsRepresentationProperty() -> DeclSyntax {
643637
return DeclSyntax(
644638
stringLiteral: """
645-
public var instructionsRepresentation: Instructions {
639+
nonisolated public var instructionsRepresentation: Instructions {
646640
return Instructions(self.generatedContent.jsonString)
647641
}
648642
"""
@@ -652,7 +646,7 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
652646
private static func generatePromptRepresentationProperty() -> DeclSyntax {
653647
return DeclSyntax(
654648
stringLiteral: """
655-
public var promptRepresentation: Prompt {
649+
nonisolated public var promptRepresentation: Prompt {
656650
return Prompt(self.generatedContent.jsonString)
657651
}
658652
"""
@@ -720,16 +714,15 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
720714

721715
return DeclSyntax(
722716
stringLiteral: """
723-
public init(_ generatedContent: GeneratedContent) throws {
724-
717+
nonisolated public init(_ generatedContent: GeneratedContent) throws {
725718
do {
726719
guard case .structure(let properties, _) = generatedContent.kind else {
727720
throw DecodingError.typeMismatch(
728721
\(enumName).self,
729722
DecodingError.Context(codingPath: [], debugDescription: "Expected structure for enum \(enumName)")
730723
)
731724
}
732-
725+
733726
guard case .string(let caseValue) = properties["case"]?.kind else {
734727
struct Key: CodingKey {
735728
var stringValue: String
@@ -742,9 +735,9 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
742735
DecodingError.Context(codingPath: [], debugDescription: "Missing 'case' property in enum data for \(enumName)")
743736
)
744737
}
745-
738+
746739
let valueContent = properties["value"]
747-
740+
748741
switch caseValue {
749742
\(switchCases)
750743
default:
@@ -775,15 +768,15 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
775768

776769
return DeclSyntax(
777770
stringLiteral: """
778-
public init(_ generatedContent: GeneratedContent) throws {
771+
nonisolated public init(_ generatedContent: GeneratedContent) throws {
779772
guard case .string(let value) = generatedContent.kind else {
780773
throw DecodingError.typeMismatch(
781774
\(enumName).self,
782775
DecodingError.Context(codingPath: [], debugDescription: "Expected string for enum \(enumName)")
783776
)
784777
}
785778
let trimmedValue = value.trimmingCharacters(in: .whitespacesAndNewlines)
786-
779+
787780
switch trimmedValue {
788781
\(switchCases)
789782
default:
@@ -942,7 +935,7 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
942935

943936
return DeclSyntax(
944937
stringLiteral: """
945-
public var generatedContent: GeneratedContent {
938+
nonisolated public var generatedContent: GeneratedContent {
946939
switch self {
947940
\(switchCases)
948941
}
@@ -956,7 +949,7 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
956949

957950
return DeclSyntax(
958951
stringLiteral: """
959-
public var generatedContent: GeneratedContent {
952+
nonisolated public var generatedContent: GeneratedContent {
960953
switch self {
961954
\(switchCases)
962955
}
@@ -1059,8 +1052,7 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
10591052

10601053
return DeclSyntax(
10611054
stringLiteral: """
1062-
public static var generationSchema: GenerationSchema {
1063-
1055+
nonisolated public static var generationSchema: GenerationSchema {
10641056
return GenerationSchema(
10651057
type: Self.self,
10661058
description: \(description.map { "\"\($0)\"" } ?? "\"Generated \(enumName)\""),
@@ -1077,8 +1069,7 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
10771069

10781070
return DeclSyntax(
10791071
stringLiteral: """
1080-
public static var generationSchema: GenerationSchema {
1081-
1072+
nonisolated public static var generationSchema: GenerationSchema {
10821073
return GenerationSchema(
10831074
type: Self.self,
10841075
description: \(description.map { "\"\($0)\"" } ?? "\"Generated \(enumName)\""),

Tests/AnyLanguageModelTests/GenerableMacroTests.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,31 @@ struct GenerableMacroTests {
7070
let decodedSchema = try decoder.decode(GenerationSchema.self, from: jsonData)
7171
#expect(decodedSchema.debugDescription.contains("object"))
7272
}
73+
74+
@MainActor
75+
@Generable
76+
struct MainActorIsolatedStruct {
77+
@Guide(description: "A test field")
78+
var field: String
79+
}
80+
81+
/// Test to verify @Generable works correctly with MainActor isolation.
82+
@MainActor
83+
@Test func mainActorIsolation() async throws {
84+
let generatedContent = GeneratedContent(properties: [
85+
"field": "test value"
86+
])
87+
let instance = try MainActorIsolatedStruct(generatedContent)
88+
#expect(instance.field == "test value")
89+
90+
let convertedBack = instance.generatedContent
91+
let decoded = try MainActorIsolatedStruct(convertedBack)
92+
#expect(decoded.field == "test value")
93+
94+
let schema = MainActorIsolatedStruct.generationSchema
95+
#expect(schema.debugDescription.contains("MainActorIsolatedStruct"))
96+
97+
let partiallyGenerated = instance.asPartiallyGenerated()
98+
#expect(partiallyGenerated.field == "test value")
99+
}
73100
}

0 commit comments

Comments
 (0)