Skip to content

Commit bb9681e

Browse files
committed
Swift 6
1 parent 66d37cd commit bb9681e

File tree

14 files changed

+77
-45
lines changed

14 files changed

+77
-45
lines changed

.github/workflows/blade.yml

+4-4
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ concurrency:
1515

1616
jobs:
1717
docc:
18-
runs-on: macos-13
18+
runs-on: macos-14
1919
steps:
2020
- name: Checkout Repository
2121
uses: actions/checkout@v3
2222
with:
2323
fetch-depth: 0
2424
- name: Xcode Select
25-
run: sudo xcode-select -s /Applications/Xcode_15.0.app
25+
run: sudo xcode-select -s /Applications/Xcode_16.2.app
2626
- name: Build Docs
2727
run: swift package --allow-writing-to-directory .docs generate-documentation --target Blade --disable-indexing --transform-for-static-hosting --hosting-base-path "/swift-blade" --output-path .docs
2828
- name: Upload Pages Artifact
@@ -34,14 +34,14 @@ jobs:
3434
uses: actions/deploy-pages@v2
3535

3636
test-mac:
37-
runs-on: macos-13
37+
runs-on: macos-14
3838
steps:
3939
- name: Checkout Repository
4040
uses: actions/checkout@v3
4141
with:
4242
fetch-depth: 0
4343
- name: Xcode Select
44-
run: sudo xcode-select -s /Applications/Xcode_15.0.app
44+
run: sudo xcode-select -s /Applications/Xcode_16.2.app
4545
- name: Run Tests
4646
run: swift test
4747

Package.resolved

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
2+
"originHash" : "b3761ba17478a3fdba923bf12ebdb4f8812fa881214f83bbd2515e8cc2b97238",
23
"pins" : [
34
{
45
"identity" : "swift-docc-plugin",
@@ -23,10 +24,10 @@
2324
"kind" : "remoteSourceControl",
2425
"location" : "https://github.com/apple/swift-syntax.git",
2526
"state" : {
26-
"revision" : "74203046135342e4a4a627476dd6caf8b28fe11b",
27-
"version" : "509.0.0"
27+
"revision" : "1103c45ece4f7fe160b8f75b4ea1ee2e5fac1841",
28+
"version" : "601.0.0"
2829
}
2930
}
3031
],
31-
"version" : 2
32+
"version" : 3
3233
}

Package.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// swift-tools-version: 5.9
1+
// swift-tools-version: 6.0
22
// The swift-tools-version declares the minimum version of Swift required to build this package.
33

44
import PackageDescription
@@ -18,7 +18,7 @@ let package = Package(
1818
],
1919
dependencies: [
2020
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.3.0"),
21-
.package(url: "https://github.com/apple/swift-syntax.git", from: "509.0.0"),
21+
.package(url: "https://github.com/apple/swift-syntax.git", from: "601.0.0"),
2222
],
2323
targets: [
2424
.target(

README.md

+3-10
Original file line numberDiff line numberDiff line change
@@ -75,19 +75,16 @@ In order to do so, swift-blade must be told how to obtain instances of each type
7575

7676
Let's go back in and add the `@Provider` attribute to the initializers of our classes so that swift-blade knows how to obtain instances of them.”
7777

78-
> [!NOTE]
79-
> An initializer-based `@Provider` must have its return type specified via the `@Provider` attribute's `of` parameter.
80-
8178
```swift
8279
class ElectricHeater: Heater {
83-
@Provider(of: ElectricHeater.self)
80+
@Provider
8481
init() {}
8582
}
8683

8784
class Thermosiphon: Pump {
8885
private let heater: Heater
8986

90-
@Provider(of: Thermosiphon.self)
87+
@Provider
9188
init(heater: Heater) {
9289
self.heater = heater
9390
}
@@ -97,7 +94,7 @@ class CoffeeMaker {
9794
private let heater: Heater
9895
private let pump: Pump
9996

100-
@Provider(of: CoffeeMaker.self)
97+
@Provider
10198
init(heater: Heater, pump: Pump) {
10299
self.heater = heater
103100
self.pump = pump
@@ -193,7 +190,3 @@ See [API Documentation](https://shackley.io/swift-blade/documentation/blade/) fo
193190
**Q: How is the dependency graph validated?**
194191

195192
Unlike Dagger, a Blade component's dependency graph is validated at runtime immediately upon component initialization. If a dependency does not have a registered provider, a `fatalError` will occur. This is largely due to the fact that the current [macro](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/macros/) implementation does not have context APIs that allow a macro to glean semantic information about types found in a delcaration at the time of expansion. If such an APIs were to be added, this validation could potentially occurr at compile time.
196-
197-
**Q: Why do `@Provider`s attached to initializers have to specify their provided type?**
198-
199-
Currently, swift macros are not provided with any lexical scope information at the time of expansion, so it isn't possible for a `@Provider` macro to know which type the initializer belongs to otherwise.

Sources/Blade/Blade.docc/Pages/AdvancedUsage/InstanceBinding.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ The values passed into the initializer can then be automatically provided as dep
2424
class CoffeeMaker {
2525
private let configuration: Configuration
2626

27-
@Provider(of: CoffeeMaker.self)
27+
@Provider
2828
init(configuration: Configuration) {
2929
self.configuration = configuration
3030
}

Sources/Blade/Blade.docc/Pages/AdvancedUsage/LazyDependencies.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Any dependency of type `T` can be substituted with a `Lazy<T>`. The object won't
1414
class GrindingCoffeeMaker {
1515
private let grinder: Lazy<Grinder>
1616

17-
@Provider(of: GrindingCoffeeMaker.self)
17+
@Provider
1818
init(grinder: Lazy<Grinder>) {
1919
self.grinder = grinder
2020
}

Sources/Blade/Blade.docc/Pages/AdvancedUsage/NamedDependencies.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class DualBoilerCoffeeMaker {
1313
private let waterHeater: Heater
1414
private let milkHeater: Heater
1515

16-
@Provider(of: DualBoilerCoffeeMaker.self)
16+
@Provider
1717
init(
1818
@Named("water") waterHeater: Heater,
1919
@Named("milk") milkHeater: Heater

Sources/Blade/Blade.docc/Pages/Basics/Providers.md

+2-4
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,11 @@ Adding the `@Provider` attribute to an initializer will allow swift-blade to pro
1616

1717
The parameters of the type's initializer are its dependencies. When a new instance of that type is needed, swift-blade will obtain instances of all of its dependencies and invoke its initializer.
1818

19-
> An initializer-based `@Provider` must have its return type specified via the `@Provider` attribute's `of` parameter.
20-
2119
```swift
2220
class Thermosiphon: Pump {
2321
private let heater: Heater
2422

25-
@Provider(of: Thermosiphon.self)
23+
@Provider
2624
init(heater: Heater) {
2725
self.heater = heater
2826
}
@@ -59,4 +57,4 @@ This pattern is commonly used to alias a concrete type to a protocol that it con
5957

6058
## Topics
6159

62-
- ``Provider(of:scope:named:)``
60+
- ``Provider(scope:named:)``

Sources/Blade/Provider.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
/// When an instance of a specific type is required, the provider function that matches that type will be invoked to obtain one.
88
///
99
/// - Parameters:
10-
/// - of: Specifies the type that is being provided. This parameter is only necessary for initializer-based providers.
10+
/// - of: This parameter is deprecated and will be removed in future versions of swift-blade.
1111
/// - scope: Defines the lifecycle of a provided instance.
1212
/// - named: Used to distinguish between multiple provider functions that return the same type.
1313
@attached(peer, names: named(_$BladeDependencyProvider))

Sources/BladePlugin/Diagnostics/BladeDiagnosticMessage.swift

+7-7
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,6 @@ extension BladeDiagnosticMessage {
8383
severity: .error
8484
)
8585

86-
static let missingProviderInitializerReturnType = BladeDiagnosticMessage(
87-
message: "An initializer-based @Provider must have its provided type specified via the @Provider attributes `of` parameter",
88-
id: "missing_provider_initializer_return_type",
89-
severity: .error
90-
)
91-
9286
static let missingProviderFunctionReturnType = BladeDiagnosticMessage(
9387
message: "@Provider functions must return a non-Void type",
9488
id: "missing_provider_function_binding_return_type",
@@ -107,8 +101,14 @@ extension BladeDiagnosticMessage {
107101
severity: .error
108102
)
109103

104+
static let unknownProviderReturnType = BladeDiagnosticMessage(
105+
message: "Unable to determine return type for initializer-based @Provider",
106+
id: "unknown_provider_return_type",
107+
severity: .error
108+
)
109+
110110
static let unnecessaryProviderFunctionReturnType = BladeDiagnosticMessage(
111-
message: "Specifying the provided type is only necessary for initializer-based @Providers",
111+
message: "Specifying the provided type is no longer necessary. The `of` parameter will be removed in future versions of swift-blade.",
112112
id: "unnecessary_provider_function_binding_return_type",
113113
severity: .warning
114114
)

Sources/BladePlugin/Macros/ProviderMacro.swift

+13-2
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,21 @@ public struct ProviderMacro: PeerMacro {
2626
context: context
2727
)
2828

29-
guard let returnType = attribute.returnType else {
29+
if attribute.returnType != nil {
3030
context.diagnose(
3131
node: node,
32-
message: .missingProviderInitializerReturnType
32+
message: .unnecessaryProviderFunctionReturnType
33+
)
34+
}
35+
36+
let providerContext = ProviderContextParser.parse(
37+
lexicalContext: context.lexicalContext
38+
)
39+
40+
guard let returnType = providerContext.type else {
41+
context.diagnose(
42+
node: node,
43+
message: .unknownProviderReturnType
3344
)
3445
return []
3546
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
struct ProviderContext {
2+
let type: String?
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import Foundation
2+
import SwiftSyntax
3+
import SwiftSyntaxMacros
4+
5+
enum ProviderContextParser {
6+
static func parse(
7+
lexicalContext: [Syntax]
8+
) -> ProviderContext {
9+
let type: String? = {
10+
for syntax in lexicalContext {
11+
if let classDecl = syntax.as(ClassDeclSyntax.self) {
12+
return classDecl.name.text
13+
} else if let structDecl = syntax.as(StructDeclSyntax.self) {
14+
return structDecl.name.text
15+
} else if let enumDecl = syntax.as(EnumDeclSyntax.self) {
16+
return enumDecl.name.text
17+
}
18+
}
19+
return nil
20+
}()
21+
22+
return ProviderContext(
23+
type: type
24+
)
25+
}
26+
}

Tests/BladeTests/BladeTests.swift

+9-9
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ public struct Config {
1212
}
1313

1414
public class FooImpl: Foo {
15-
public static var initializations: Int = 0
15+
nonisolated(unsafe) public static var initializations: Int = 0
1616
private let config: Config
1717
private let key1: String
1818
private let key2: String
1919

20-
@Provider(of: FooImpl.self)
20+
@Provider
2121
public init(
2222
config: Config,
2323
@Named("key1") key1: String,
@@ -31,21 +31,21 @@ public class FooImpl: Foo {
3131
}
3232

3333
public class BarImpl: Bar {
34-
public static var initializations: Int = 0
34+
nonisolated(unsafe) public static var initializations: Int = 0
3535
private let foo: Lazy<Foo>
3636

37-
@Provider(of: BarImpl.self)
37+
@Provider
3838
public init(foo: Lazy<Foo>) {
3939
self.foo = foo
4040
Self.initializations += 1
4141
}
4242
}
4343

4444
public class BazImpl: Baz {
45-
public static var initializations: Int = 0
45+
nonisolated(unsafe) public static var initializations: Int = 0
4646
private let foo: Foo
4747

48-
@Provider(of: BazImpl.self, scope: .singleton)
48+
@Provider(scope: .singleton)
4949
public init(foo: Foo) {
5050
self.foo = foo
5151
Self.initializations += 1
@@ -61,7 +61,7 @@ struct B {
6161
}
6262

6363
struct C {
64-
@Provider(of: C.self)
64+
@Provider
6565
init() {}
6666
}
6767

@@ -72,11 +72,11 @@ struct ABC {
7272
}
7373

7474
public class Alphabet {
75-
public static var initializations: Int = 0
75+
nonisolated(unsafe) public static var initializations: Int = 0
7676
private let abc: ABC
7777
private let key1: String
7878

79-
@Provider(of: Alphabet.self, scope: .singleton)
79+
@Provider(scope: .singleton)
8080
init(abc: ABC, @Named("key1") key1: String) {
8181
self.abc = abc
8282
self.key1 = key1

0 commit comments

Comments
 (0)