From c7d545bcc7c0b6fc9f92bec5fd4c17f820355d37 Mon Sep 17 00:00:00 2001 From: funsaized Date: Sun, 5 Jul 2026 13:55:40 -0400 Subject: [PATCH] =?UTF-8?q?fix(tests):=20break=20up=20B=C3=A9zier=20expres?= =?UTF-8?q?sions=20that=20time=20out=20Swift=20type-checking?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI on main fails compiling ScreenOutlineTests.swift under Xcode 26.3: "the compiler is unable to type-check this expression in reasonable time" at the applyWithBlock closure in flattenedPoints. The chained quad/cubic Bézier arithmetic mixing untyped integer literals with CGFloat inside an inferred closure blows the type-checker's budget. Hoist the sampling math into quadPoint/cubicPoint helpers with explicitly typed CGFloat coefficients, as the diagnostic suggests. No behavior change; all 41 tests pass. Co-Authored-By: Claude Fable 5 --- .../ScreenOutlineTests.swift | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/Tests/PowerSnekKitTests/ScreenOutlineTests.swift b/Tests/PowerSnekKitTests/ScreenOutlineTests.swift index 3e066ca..be8ee59 100644 --- a/Tests/PowerSnekKitTests/ScreenOutlineTests.swift +++ b/Tests/PowerSnekKitTests/ScreenOutlineTests.swift @@ -101,6 +101,27 @@ private func pathElements(_ path: CGPath) -> [PathElement] { return result } +/// Kept out of the `applyWithBlock` closure: inlining these Bézier +/// expressions makes Swift 6 type-checking blow past its time budget. +private func quadPoint(_ t: CGFloat, _ p0: CGPoint, _ c: CGPoint, _ p1: CGPoint) -> CGPoint { + let mt: CGFloat = 1 - t + let a: CGFloat = mt * mt + let b: CGFloat = 2 * mt * t + let d: CGFloat = t * t + return CGPoint(x: a * p0.x + b * c.x + d * p1.x, + y: a * p0.y + b * c.y + d * p1.y) +} + +private func cubicPoint(_ t: CGFloat, _ p0: CGPoint, _ c1: CGPoint, _ c2: CGPoint, _ p1: CGPoint) -> CGPoint { + let mt: CGFloat = 1 - t + let a: CGFloat = mt * mt * mt + let b: CGFloat = 3 * mt * mt * t + let c: CGFloat = 3 * mt * t * t + let d: CGFloat = t * t * t + return CGPoint(x: a * p0.x + b * c1.x + c * c2.x + d * p1.x, + y: a * p0.y + b * c1.y + c * c2.y + d * p1.y) +} + /// Flattens curves into sampled points so lengths/positions can be /// measured independently of the analytic bookkeeping under test. private func flattenedPoints(_ path: CGPath, samplesPerCurve: Int = 64) -> [CGPoint] { @@ -116,17 +137,14 @@ private func flattenedPoints(_ path: CGPath, samplesPerCurve: Int = 64) -> [CGPo case .addQuadCurveToPoint: let p0 = pts.last ?? .zero, c = e.points[0], p1 = e.points[1] for i in 1...samplesPerCurve { - let t = CGFloat(i) / CGFloat(samplesPerCurve), mt = 1 - t - pts.append(CGPoint(x: mt * mt * p0.x + 2 * mt * t * c.x + t * t * p1.x, - y: mt * mt * p0.y + 2 * mt * t * c.y + t * t * p1.y)) + let t = CGFloat(i) / CGFloat(samplesPerCurve) + pts.append(quadPoint(t, p0, c, p1)) } case .addCurveToPoint: let p0 = pts.last ?? .zero, c1 = e.points[0], c2 = e.points[1], p1 = e.points[2] for i in 1...samplesPerCurve { - let t = CGFloat(i) / CGFloat(samplesPerCurve), mt = 1 - t - pts.append(CGPoint( - x: mt * mt * mt * p0.x + 3 * mt * mt * t * c1.x + 3 * mt * t * t * c2.x + t * t * t * p1.x, - y: mt * mt * mt * p0.y + 3 * mt * mt * t * c1.y + 3 * mt * t * t * c2.y + t * t * t * p1.y)) + let t = CGFloat(i) / CGFloat(samplesPerCurve) + pts.append(cubicPoint(t, p0, c1, c2, p1)) } case .closeSubpath: pts.append(start)