Skip to content

Commit b0be207

Browse files
committed
Make EC a class
1 parent 3009cf2 commit b0be207

File tree

7 files changed

+136
-124
lines changed

7 files changed

+136
-124
lines changed

Package.swift

+1
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ extension Array where Element == PackageDescription.SwiftSetting {
159159
.unsafeFlags(["-require-explicit-sendable"]),
160160
.enableUpcomingFeature("ExistentialAny"),
161161
.enableExperimentalFeature("SuppressedAssociatedTypes"),
162+
.enableExperimentalFeature("NonescapableTypes"),
162163

163164
.enableExperimentalFeature("AccessLevelOnImport"),
164165
.enableUpcomingFeature("InternalImportsByDefault"),

Sources/Testing/Expectations/ExpectationChecking+Macro.swift

+14-14
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,14 @@ func check(
105105
/// - Warning: This function is used to implement the `#expect()` and
106106
/// `#require()` macros. Do not call it directly.
107107
public func __checkCondition(
108-
_ condition: (inout __ExpectationContext) throws -> Bool,
108+
_ condition: (__ExpectationContext) throws -> Bool,
109109
sourceCode: @escaping @autoclosure @Sendable () -> [__ExpressionID: String],
110110
comments: @autoclosure () -> [Comment],
111111
isRequired: Bool,
112112
sourceLocation: SourceLocation
113113
) rethrows -> Result<Void, any Error> {
114-
var expectationContext = __ExpectationContext.init(sourceCode: sourceCode())
115-
let condition = try condition(&expectationContext)
114+
let expectationContext = __ExpectationContext.init(sourceCode: sourceCode())
115+
let condition = try condition(expectationContext)
116116

117117
return check(
118118
condition,
@@ -131,14 +131,14 @@ public func __checkCondition(
131131
/// - Warning: This function is used to implement the `#expect()` and
132132
/// `#require()` macros. Do not call it directly.
133133
public func __checkCondition<T>(
134-
_ optionalValue: (inout __ExpectationContext) throws -> T?,
134+
_ optionalValue: (__ExpectationContext) throws -> T?,
135135
sourceCode: @escaping @autoclosure @Sendable () -> [__ExpressionID: String],
136136
comments: @autoclosure () -> [Comment],
137137
isRequired: Bool,
138138
sourceLocation: SourceLocation
139139
) rethrows -> Result<T, any Error> where T: ~Copyable {
140-
var expectationContext = __ExpectationContext(sourceCode: sourceCode())
141-
let optionalValue = try optionalValue(&expectationContext)
140+
let expectationContext = __ExpectationContext(sourceCode: sourceCode())
141+
let optionalValue = try optionalValue(expectationContext)
142142

143143
let result = check(
144144
optionalValue != nil,
@@ -166,15 +166,15 @@ public func __checkCondition<T>(
166166
/// - Warning: This function is used to implement the `#expect()` and
167167
/// `#require()` macros. Do not call it directly.
168168
public func __checkConditionAsync(
169-
_ condition: (inout __ExpectationContext) async throws -> Bool,
169+
_ condition: (__ExpectationContext) async throws -> Bool,
170170
sourceCode: @escaping @autoclosure @Sendable () -> [__ExpressionID: String],
171171
comments: @autoclosure () -> [Comment],
172172
isRequired: Bool,
173173
isolation: isolated (any Actor)? = #isolation,
174174
sourceLocation: SourceLocation
175175
) async rethrows -> Result<Void, any Error> {
176-
var expectationContext = __ExpectationContext(sourceCode: sourceCode())
177-
let condition = try await condition(&expectationContext)
176+
let expectationContext = __ExpectationContext(sourceCode: sourceCode())
177+
let condition = try await condition(expectationContext)
178178

179179
return check(
180180
condition,
@@ -193,15 +193,15 @@ public func __checkConditionAsync(
193193
/// - Warning: This function is used to implement the `#expect()` and
194194
/// `#require()` macros. Do not call it directly.
195195
public func __checkConditionAsync<T>(
196-
_ optionalValue: (inout __ExpectationContext) async throws -> sending T?,
196+
_ optionalValue: (__ExpectationContext) async throws -> sending T?,
197197
sourceCode: @escaping @autoclosure @Sendable () -> [__ExpressionID: String],
198198
comments: @autoclosure () -> [Comment],
199199
isRequired: Bool,
200200
isolation: isolated (any Actor)? = #isolation,
201201
sourceLocation: SourceLocation
202202
) async rethrows -> Result<T, any Error> where T: ~Copyable {
203-
var expectationContext = __ExpectationContext(sourceCode: sourceCode())
204-
let optionalValue = try await optionalValue(&expectationContext)
203+
let expectationContext = __ExpectationContext(sourceCode: sourceCode())
204+
let optionalValue = try await optionalValue(expectationContext)
205205

206206
let result = check(
207207
optionalValue != nil,
@@ -516,7 +516,7 @@ public func __checkClosureCall<R>(
516516
isRequired: Bool,
517517
sourceLocation: SourceLocation
518518
) -> Result<(any Error)?, any Error> {
519-
var expectationContext = __ExpectationContext(sourceCode: sourceCode())
519+
let expectationContext = __ExpectationContext(sourceCode: sourceCode())
520520

521521
var errorMatches = false
522522
var mismatchExplanationValue: String? = nil
@@ -569,7 +569,7 @@ public func __checkClosureCall<R>(
569569
isolation: isolated (any Actor)? = #isolation,
570570
sourceLocation: SourceLocation
571571
) async -> Result<(any Error)?, any Error> {
572-
var expectationContext = __ExpectationContext(sourceCode: sourceCode())
572+
let expectationContext = __ExpectationContext(sourceCode: sourceCode())
573573

574574
var errorMatches = false
575575
var mismatchExplanationValue: String? = nil

Sources/Testing/Expectations/ExpectationContext+Pointers.swift

+4-4
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ extension __ExpectationContext {
2828
///
2929
/// - Warning: This function is used to implement the `#expect()` and
3030
/// `#require()` macros. Do not call it directly.
31-
@inlinable public mutating func callAsFunction<P>(_ value: P, _ id: __ExpressionID) -> P where P: _Pointer {
31+
@inlinable public func callAsFunction<P>(_ value: consuming P, _ id: __ExpressionID) -> P where P: _Pointer {
3232
captureValue(value, id)
3333
}
3434

@@ -49,7 +49,7 @@ extension __ExpectationContext {
4949
///
5050
/// - Warning: This function is used to implement the `#expect()` and
5151
/// `#require()` macros. Do not call it directly.
52-
@inlinable public mutating func callAsFunction(_ value: String, _ id: __ExpressionID) -> String {
52+
@inlinable public func callAsFunction(_ value: consuming String, _ id: __ExpressionID) -> String {
5353
captureValue(value, id)
5454
}
5555

@@ -70,7 +70,7 @@ extension __ExpectationContext {
7070
///
7171
/// - Warning: This function is used to implement the `#expect()` and
7272
/// `#require()` macros. Do not call it directly.
73-
@inlinable public mutating func callAsFunction<E>(_ value: Array<E>, _ id: __ExpressionID) -> Array<E> {
73+
@inlinable public func callAsFunction<E>(_ value: consuming Array<E>, _ id: __ExpressionID) -> Array<E> {
7474
captureValue(value, id)
7575
}
7676

@@ -90,7 +90,7 @@ extension __ExpectationContext {
9090
/// - Warning: This function is used to implement the `#expect()` and
9191
/// `#require()` macros. Do not call it directly.
9292
@_disfavoredOverload
93-
@inlinable public mutating func callAsFunction<T>(_ value: T?, _ id: __ExpressionID) -> T? {
93+
@inlinable public func callAsFunction<T>(_ value: consuming T?, _ id: __ExpressionID) -> T? {
9494
captureValue(value, id)
9595
}
9696
}

Sources/Testing/Expectations/ExpectationContext.swift

+13-13
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
///
1919
/// - Warning: This type is used to implement the `#expect()` and `#require()`
2020
/// macros. Do not use it directly.
21-
public struct __ExpectationContext: ~Copyable {
21+
public final class __ExpectationContext {
2222
/// The source code representations of any captured expressions.
2323
///
2424
/// Unlike the rest of the state in this type, the source code dictionary is
@@ -167,7 +167,7 @@ extension __ExpectationContext {
167167
///
168168
/// This function helps overloads of `callAsFunction(_:_:)` disambiguate
169169
/// themselves and avoid accidental recursion.
170-
@usableFromInline mutating func captureValue<T>(_ value: T, _ id: __ExpressionID) -> T {
170+
@usableFromInline func captureValue<T>(_ value: T, _ id: __ExpressionID) -> T {
171171
runtimeValues[id] = { Expression.Value(reflecting: value) }
172172
return value
173173
}
@@ -185,7 +185,7 @@ extension __ExpectationContext {
185185
/// - Warning: This function is used to implement the `#expect()` and
186186
/// `#require()` macros. Do not call it directly.
187187
@_disfavoredOverload
188-
@inlinable public mutating func callAsFunction<T>(_ value: T, _ id: __ExpressionID) -> T {
188+
@inlinable public func callAsFunction<T>(_ value: T, _ id: __ExpressionID) -> T {
189189
captureValue(value, id)
190190
}
191191

@@ -203,7 +203,7 @@ extension __ExpectationContext {
203203
/// - Warning: This function is used to implement the `#expect()` and
204204
/// `#require()` macros. Do not call it directly.
205205
@_disfavoredOverload
206-
public mutating func callAsFunction<T>(_ value: consuming T, _ id: __ExpressionID) -> T where T: ~Copyable {
206+
public func callAsFunction<T>(_ value: consuming T, _ id: __ExpressionID) -> T where T: ~Copyable {
207207
// TODO: add support for borrowing non-copyable expressions (need @lifetime)
208208
return value
209209
}
@@ -219,7 +219,7 @@ extension __ExpectationContext {
219219
///
220220
/// - Warning: This function is used to implement the `#expect()` and
221221
/// `#require()` macros. Do not call it directly.
222-
public mutating func __inoutAfter<T>(_ value: T, _ id: __ExpressionID) {
222+
public func __inoutAfter<T>(_ value: T, _ id: __ExpressionID) {
223223
runtimeValues[id] = { Expression.Value(reflecting: value, timing: .after) }
224224
}
225225
}
@@ -272,14 +272,14 @@ extension __ExpectationContext {
272272
///
273273
/// - Warning: This function is used to implement the `#expect()` and
274274
/// `#require()` macros. Do not call it directly.
275-
@inlinable public mutating func __cmp<T, U, R>(
276-
_ op: (T, U) throws -> R,
275+
@inlinable public func __cmp<T, U>(
276+
_ op: (T, U) throws -> Bool,
277277
_ opID: __ExpressionID,
278278
_ lhs: T,
279279
_ lhsID: __ExpressionID,
280280
_ rhs: U,
281281
_ rhsID: __ExpressionID
282-
) rethrows -> R {
282+
) rethrows -> Bool {
283283
try captureValue(op(captureValue(lhs, lhsID), captureValue(rhs, rhsID)), opID)
284284
}
285285

@@ -290,7 +290,7 @@ extension __ExpectationContext {
290290
///
291291
/// - Warning: This function is used to implement the `#expect()` and
292292
/// `#require()` macros. Do not call it directly.
293-
public mutating func __cmp<C>(
293+
public func __cmp<C>(
294294
_ op: (C, C) -> Bool,
295295
_ opID: __ExpressionID,
296296
_ lhs: C,
@@ -315,7 +315,7 @@ extension __ExpectationContext {
315315
///
316316
/// - Warning: This function is used to implement the `#expect()` and
317317
/// `#require()` macros. Do not call it directly.
318-
@inlinable public mutating func __cmp<R>(
318+
@inlinable public func __cmp<R>(
319319
_ op: (R, R) -> Bool,
320320
_ opID: __ExpressionID,
321321
_ lhs: R,
@@ -334,7 +334,7 @@ extension __ExpectationContext {
334334
///
335335
/// - Warning: This function is used to implement the `#expect()` and
336336
/// `#require()` macros. Do not call it directly.
337-
public mutating func __cmp<S>(
337+
public func __cmp<S>(
338338
_ op: (S, S) -> Bool,
339339
_ opID: __ExpressionID,
340340
_ lhs: S,
@@ -392,7 +392,7 @@ extension __ExpectationContext {
392392
///
393393
/// - Warning: This function is used to implement the `#expect()` and
394394
/// `#require()` macros. Do not call it directly.
395-
@inlinable public mutating func __as<T, U>(_ value: T, _ valueID: __ExpressionID, _ type: U.Type, _ typeID: __ExpressionID) -> U? {
395+
@inlinable public func __as<T, U>(_ value: T, _ valueID: __ExpressionID, _ type: U.Type, _ typeID: __ExpressionID) -> U? {
396396
let result = captureValue(value, valueID) as? U
397397

398398
if result == nil {
@@ -421,7 +421,7 @@ extension __ExpectationContext {
421421
///
422422
/// - Warning: This function is used to implement the `#expect()` and
423423
/// `#require()` macros. Do not call it directly.
424-
@inlinable public mutating func __is<T, U>(_ value: T, _ valueID: __ExpressionID, _ type: U.Type, _ typeID: __ExpressionID) -> Bool {
424+
@inlinable public func __is<T, U>(_ value: T, _ valueID: __ExpressionID, _ type: U.Type, _ typeID: __ExpressionID) -> Bool {
425425
let result = captureValue(value, valueID) is U
426426

427427
if !result {

Sources/TestingMacros/Support/ConditionArgumentParsing.swift

+12-19
Original file line numberDiff line numberDiff line change
@@ -678,8 +678,10 @@ extension ConditionMacro {
678678
// If we're inserting any additional code into the closure before
679679
// the rewritten argument, we can't elide the return keyword.
680680
ReturnStmtSyntax(
681-
expression: expandedExpr.with(\.leadingTrivia, .space)
682-
).with(\.trailingTrivia, .newline)
681+
returnKeyword: .keyword(.return, trailingTrivia: .space),
682+
expression: expandedExpr,
683+
trailingTrivia: .space
684+
)
683685
}
684686
}
685687

@@ -715,19 +717,11 @@ extension ConditionMacro {
715717
parameters: ClosureParameterListSyntax {
716718
ClosureParameterSyntax(
717719
firstName: expressionContextName,
718-
colon: .colonToken().with(\.trailingTrivia, .space),
720+
colon: .colonToken(trailingTrivia: .space),
719721
type: TypeSyntax(
720-
AttributedTypeSyntax(
721-
specifiers: [
722-
TypeSpecifierListSyntax.Element(
723-
SimpleTypeSpecifierSyntax(specifier: .keyword(.inout))
724-
.with(\.trailingTrivia, .space)
725-
)
726-
],
727-
baseType: MemberTypeSyntax(
728-
baseType: IdentifierTypeSyntax(name: .identifier("Testing")),
729-
name: .identifier("__ExpectationContext")
730-
)
722+
MemberTypeSyntax(
723+
baseType: IdentifierTypeSyntax(name: .identifier("Testing")),
724+
name: .identifier("__ExpectationContext")
731725
)
732726
)
733727
)
@@ -736,12 +730,11 @@ extension ConditionMacro {
736730
),
737731
returnClause: returnType.map { returnType in
738732
ReturnClauseSyntax(
739-
type: returnType.with(\.leadingTrivia, .space)
740-
).with(\.leadingTrivia, .space)
733+
arrow: .arrowToken(leadingTrivia: .space, trailingTrivia: .space),
734+
type: returnType
735+
)
741736
},
742-
inKeyword: .keyword(.in)
743-
.with(\.leadingTrivia, .space)
744-
.with(\.trailingTrivia, .newline)
737+
inKeyword: .keyword(.in, leadingTrivia: .space, trailingTrivia: .space)
745738
),
746739
statements: codeBlockItems
747740
)

Tests/SubexpressionShowcase/SubexpressionShowcase.swift

+22-4
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,15 @@ struct T {
3737
}
3838

3939
func subexpressionShowcase() async throws {
40+
let fff = false
41+
let ttt = true
4042
#expect(false || true)
43+
44+
#expect((fff == ttt) == ttt)
45+
Testing.__checkCondition({(__ec: Testing.__ExpectationContext) -> Swift.Bool in
46+
__ec.__cmp(==,0x0,__ec((__ec.__cmp(==,0x3a,__ec(fff,0x7a),0x7a,__ec(ttt,0x43a),0x43a)),0x2),0x2,__ec(ttt,0x8000),0x8000)
47+
},sourceCode: [0x0:"(fff == ttt) == ttt",0x2:"(fff == ttt)",0x3a:"fff == ttt",0x7a:"fff",0x43a:"ttt",0x8000:"ttt"],comments: [],isRequired: false,sourceLocation: Testing.SourceLocation.__here()).__expected()
48+
4149
#expect((Int)(123) == 124)
4250
#expect((Int, Double)(123, 456.0) == (124, 457.0))
4351
#expect((123, 456) == (789, 0x12))
@@ -101,11 +109,21 @@ func subexpressionShowcase() async throws {
101109
}
102110
#expect(await k(true))
103111

112+
func k2(_ x: @escaping @autoclosure () -> Bool) async -> Bool {
113+
x()
114+
}
115+
#expect(await k2(true))
116+
104117
#if false
105-
// Unsupported: __ec is necessarily inout and captures non-sendable state, so
106-
// this will fail to compile. Making __ec a class instead is possible, but
107-
// adds a very large amount of code and locking overhead for what we can
108-
// assume is an edge case.
118+
// Unsupported: __ec necessarily captures non-sendable state, so this will
119+
// fail to compile because it is capturing __ec in a sendable closure. We
120+
// could add locks guarding __ec's mutable state and eagerly capture state,
121+
// but that would slow down tests significantly. The type checker cannot
122+
// handle the number of `where T: Sendable` overloads of various functions
123+
// that we would need in order to provide eager capture only for non-sendable
124+
// values. However, this is a relatively narrow case, so for now we'll just
125+
// accept it as unsupported and tell affected test authors to refactor their
126+
// expectations so as to call m(_:) _before_ #expect().
109127
func m(_ x: @autoclosure @Sendable () -> Bool) -> Bool {
110128
x()
111129
}

0 commit comments

Comments
 (0)