Skip to content

Commit c084339

Browse files
authored
Generate peer classes of an imported typealias (#70)
pkl-gen-swift doesn't generate the classes for imports if you only reference a typealias from an import that also has classes. When you gather a typealias, we should also gather the enclosing module, so we pickup any adjacent classes to the typealias. This also adds a test case that fails if you remove this patch (so you can confirm the fix).
1 parent a1ac94e commit c084339

File tree

6 files changed

+97
-1
lines changed

6 files changed

+97
-1
lines changed

Package.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ let package = Package(
9494
"Fixtures/Poly.pkl",
9595
"Fixtures/ApiTypes.pkl",
9696
"Fixtures/Collections2.pkl",
97+
"Fixtures/UnusedClass.pkl",
98+
"Fixtures/Imports/UnusedClassDefs.pkl",
9799
],
98100
swiftSettings: [.enableUpcomingFeature("StrictConcurrency")]
99101
),
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Code generated from Pkl module `UnusedClass`. DO NOT EDIT.
2+
import PklSwift
3+
4+
public enum UnusedClass {}
5+
6+
extension UnusedClass {
7+
public struct Module: PklRegisteredType, Decodable, Hashable, Sendable {
8+
public static let registeredIdentifier: String = "UnusedClass"
9+
10+
public var referencedAlias: UnusedClassDefs.ReferencedAlias
11+
12+
public init(referencedAlias: UnusedClassDefs.ReferencedAlias) {
13+
self.referencedAlias = referencedAlias
14+
}
15+
}
16+
17+
/// Load the Pkl module at the given source and evaluate it into `UnusedClass.Module`.
18+
///
19+
/// - Parameter source: The source of the Pkl module.
20+
public static func loadFrom(source: ModuleSource) async throws -> UnusedClass.Module {
21+
try await PklSwift.withEvaluator { evaluator in
22+
try await loadFrom(evaluator: evaluator, source: source)
23+
}
24+
}
25+
26+
/// Load the Pkl module at the given source and evaluate it with the given evaluator into
27+
/// `UnusedClass.Module`.
28+
///
29+
/// - Parameter evaluator: The evaluator to use for evaluation.
30+
/// - Parameter source: The module to evaluate.
31+
public static func loadFrom(
32+
evaluator: PklSwift.Evaluator,
33+
source: PklSwift.ModuleSource
34+
) async throws -> UnusedClass.Module {
35+
try await evaluator.evaluateModule(source: source, as: Module.self)
36+
}
37+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Code generated from Pkl module `UnusedClassDefs`. DO NOT EDIT.
2+
import PklSwift
3+
4+
public enum UnusedClassDefs {}
5+
6+
extension UnusedClassDefs {
7+
public struct Module: PklRegisteredType, Decodable, Hashable, Sendable {
8+
public static let registeredIdentifier: String = "UnusedClassDefs"
9+
10+
public init() {}
11+
}
12+
13+
public struct ThisClassShouldAlsoGenerate: PklRegisteredType, Decodable, Hashable, Sendable {
14+
public static let registeredIdentifier: String = "UnusedClassDefs#ThisClassShouldAlsoGenerate"
15+
16+
public init() {}
17+
}
18+
19+
public typealias ReferencedAlias = String
20+
21+
/// Load the Pkl module at the given source and evaluate it into `UnusedClassDefs.Module`.
22+
///
23+
/// - Parameter source: The source of the Pkl module.
24+
public static func loadFrom(source: ModuleSource) async throws -> UnusedClassDefs.Module {
25+
try await PklSwift.withEvaluator { evaluator in
26+
try await loadFrom(evaluator: evaluator, source: source)
27+
}
28+
}
29+
30+
/// Load the Pkl module at the given source and evaluate it with the given evaluator into
31+
/// `UnusedClassDefs.Module`.
32+
///
33+
/// - Parameter evaluator: The evaluator to use for evaluation.
34+
/// - Parameter source: The module to evaluate.
35+
public static func loadFrom(
36+
evaluator: PklSwift.Evaluator,
37+
source: PklSwift.ModuleSource
38+
) async throws -> UnusedClassDefs.Module {
39+
try await evaluator.evaluateModule(source: source, as: Module.self)
40+
}
41+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
typealias ReferencedAlias = String
2+
3+
class ThisClassShouldAlsoGenerate {
4+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import "Imports/UnusedClassDefs.pkl" as defs
2+
3+
// This test imports UnusedClassDefs, but it ONLY references the typealias and
4+
// not any of the classes. This caused the Module to be elided by the generator,
5+
// which results in a compilation failure.
6+
referencedAlias: defs.ReferencedAlias

codegen/src/internal/gatherer.pkl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,13 @@ function gatherTypeDeclarations(
4242
|> gatherModuleTypeAliases(decl)
4343
|> gatherModule(decl)
4444
else if (decl is reflect.TypeAlias)
45-
seen.add(decl) |> gatherTypeArguments(decl)
45+
// If you reference a TypeAlias, gather that alias as well as all of the
46+
// other declarations in alias's module. This resolves the issue where a
47+
// caller only references a type alias from a module, which would cause
48+
// the alias's sibling classes to not generate.
49+
seen.add(decl)
50+
|> gatherTypeArguments(decl)
51+
|> (seen: List<reflect.TypeDeclaration>) -> gatherTypeDeclarations(decl.enclosingDeclaration.moduleClass, seen)
4652
else seen
4753

4854
/// Tells if this class is part of the stdlib.

0 commit comments

Comments
 (0)