Skip to content

Commit cb7755b

Browse files
authored
reduce use of preconditions and asserts (#4169)
motivation: better robustness changes: replace use of preconditions and asserts with throwing guards
1 parent 18f7b44 commit cb7755b

20 files changed

+127
-90
lines changed

Sources/Build/BuildPlan.swift

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,10 @@ public final class ClangTargetBuildDescription {
278278

279279
/// Create a new target description with target and build parameters.
280280
init(target: ResolvedTarget, toolsVersion: ToolsVersion, buildParameters: BuildParameters, fileSystem: FileSystem) throws {
281-
assert(target.underlyingTarget is ClangTarget, "underlying target type mismatch \(target)")
281+
guard target.underlyingTarget is ClangTarget else {
282+
throw InternalError("underlying target type mismatch \(target)")
283+
}
284+
282285
self.fileSystem = fileSystem
283286
self.target = target
284287
self.toolsVersion = toolsVersion
@@ -637,7 +640,9 @@ public final class SwiftTargetBuildDescription {
637640
isTestDiscoveryTarget: Bool = false,
638641
fileSystem: FileSystem
639642
) throws {
640-
assert(target.underlyingTarget is SwiftTarget, "underlying target type mismatch \(target)")
643+
guard target.underlyingTarget is SwiftTarget else {
644+
throw InternalError("underlying target type mismatch \(target)")
645+
}
641646
self.target = target
642647
self.toolsVersion = toolsVersion
643648
self.buildParameters = buildParameters
@@ -870,7 +875,9 @@ public final class SwiftTargetBuildDescription {
870875

871876
/// Command-line for emitting just the Swift module.
872877
public func emitModuleCommandLine() throws -> [String] {
873-
assert(buildParameters.emitSwiftModuleSeparately)
878+
guard buildParameters.emitSwiftModuleSeparately else {
879+
throw InternalError("expecting emitSwiftModuleSeparately in build parameters")
880+
}
874881

875882
var result: [String] = []
876883
result.append(buildParameters.toolchain.swiftCompiler.pathString)
@@ -915,7 +922,9 @@ public final class SwiftTargetBuildDescription {
915922
///
916923
/// Note: This doesn't emit the module.
917924
public func emitObjectsCommandLine() throws -> [String] {
918-
assert(buildParameters.emitSwiftModuleSeparately)
925+
guard buildParameters.emitSwiftModuleSeparately else {
926+
throw InternalError("expecting emitSwiftModuleSeparately in build parameters")
927+
}
919928

920929
var result: [String] = []
921930
result.append(buildParameters.toolchain.swiftCompiler.pathString)
@@ -1183,8 +1192,11 @@ public final class ProductBuildDescription {
11831192
private let observabilityScope: ObservabilityScope
11841193

11851194
/// Create a build description for a product.
1186-
init(product: ResolvedProduct, toolsVersion: ToolsVersion, buildParameters: BuildParameters, fileSystem: FileSystem, observabilityScope: ObservabilityScope) {
1187-
assert(product.type != .library(.automatic), "Automatic type libraries should not be described.")
1195+
init(product: ResolvedProduct, toolsVersion: ToolsVersion, buildParameters: BuildParameters, fileSystem: FileSystem, observabilityScope: ObservabilityScope) throws {
1196+
guard product.type != .library(.automatic) else {
1197+
throw InternalError("Automatic type libraries should not be described.")
1198+
}
1199+
11881200
self.product = product
11891201
self.toolsVersion = toolsVersion
11901202
self.buildParameters = buildParameters
@@ -1293,11 +1305,12 @@ public final class ProductBuildDescription {
12931305
// a main symbol named that way to allow tests to link against it without
12941306
// conflicts. If we're using a linker that doesn't support symbol renaming,
12951307
// we will instead have generated a source file containing the redirect.
1296-
// Support for linking tests againsts executables is conditional on the tools
1308+
// Support for linking tests against executables is conditional on the tools
12971309
// version of the package that defines the executable product.
1298-
if product.executableModule.underlyingTarget is SwiftTarget, toolsVersion >= .v5_5,
1310+
let executableTarget = try product.executableTarget()
1311+
if executableTarget.underlyingTarget is SwiftTarget, toolsVersion >= .v5_5,
12991312
buildParameters.canRenameEntrypointFunctionName {
1300-
if let flags = buildParameters.linkerFlagsForRenamingMainFunction(of: product.executableModule) {
1313+
if let flags = buildParameters.linkerFlagsForRenamingMainFunction(of: executableTarget) {
13011314
args += flags
13021315
}
13031316
}
@@ -1456,7 +1469,10 @@ public final class PluginDescription: Codable {
14561469
testDiscoveryTarget: Bool = false,
14571470
fileSystem: FileSystem
14581471
) throws {
1459-
assert(target.underlyingTarget is PluginTarget, "underlying target type mismatch \(target)")
1472+
guard target.underlyingTarget is PluginTarget else {
1473+
throw InternalError("underlying target type mismatch \(target)")
1474+
}
1475+
14601476
self.package = package.identity
14611477
self.targetName = target.name
14621478
self.productNames = products.map{ $0.name }
@@ -1728,7 +1744,7 @@ public class BuildPlan {
17281744
// Determine the appropriate tools version to use for the product.
17291745
// This can affect what flags to pass and other semantics.
17301746
let toolsVersion = graph.package(for: product)?.manifest.toolsVersion ?? .v5_5
1731-
productMap[product] = ProductBuildDescription(
1747+
productMap[product] = try ProductBuildDescription(
17321748
product: product,
17331749
toolsVersion: toolsVersion,
17341750
buildParameters: buildParameters,

Sources/Build/LLBuildManifestBuilder.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -549,8 +549,8 @@ extension LLBuildManifestBuilder {
549549
// Depend on the binary for executable targets.
550550
if target.type == .executable {
551551
// FIXME: Optimize.
552-
let _product = plan.graph.allProducts.first {
553-
$0.type == .executable && $0.executableModule == target
552+
let _product = try plan.graph.allProducts.first {
553+
try $0.type == .executable && $0.executableTarget() == target
554554
}
555555
if let product = _product {
556556
guard let planProduct = plan.productMap[product] else {

Sources/PackageGraph/Pubgrub/Incompatibility.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,9 @@ public struct Incompatibility: Equatable, Hashable {
4545
}
4646

4747
let normalizedTerms = try normalize(terms: terms.elements)
48-
assert(normalizedTerms.count > 0,
49-
"An incompatibility must contain at least one term after normalization.")
48+
guard normalizedTerms.count > 0 else {
49+
throw InternalError("An incompatibility must contain at least one term after normalization.")
50+
}
5051
self.init(terms: OrderedSet(normalizedTerms), cause: cause)
5152
}
5253
}

Sources/PackageGraph/Pubgrub/PubgrubDependencyResolver.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,9 @@ public struct PubgrubDependencyResolver {
227227
let updatePackage = try container.underlying.loadPackageReference(at: boundVersion)
228228

229229
if var existing = flattenedAssignments[updatePackage] {
230-
assert(existing.binding == boundVersion, "Two products in one package resolved to different versions: \(existing.products)@\(existing.binding) vs \(products)@\(boundVersion)")
230+
guard existing.binding == boundVersion else {
231+
throw InternalError("Two products in one package resolved to different versions: \(existing.products)@\(existing.binding) vs \(products)@\(boundVersion)")
232+
}
231233
existing.products.formUnion(products)
232234
flattenedAssignments[updatePackage] = existing
233235
} else {
@@ -284,7 +286,9 @@ public struct PubgrubDependencyResolver {
284286

285287
// Mark the package as overridden.
286288
if var existing = overriddenPackages[constraint.package] {
287-
assert(existing.version == .unversioned, "Overridden package is not unversioned: \(constraint.package)@\(existing.version)")
289+
guard existing.version == .unversioned else {
290+
throw InternalError("Overridden package is not unversioned: \(constraint.package)@\(existing.version)")
291+
}
288292
existing.products.formUnion(constraint.products)
289293
overriddenPackages[constraint.package] = existing
290294
} else {

Sources/PackageGraph/ResolvedProduct.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
99
*/
1010

11+
import Basics
1112
import TSCBasic
1213
import PackageModel
1314

@@ -34,8 +35,10 @@ public final class ResolvedProduct {
3435
/// The main executable target of product.
3536
///
3637
/// Note: This property is only valid for executable products.
37-
public var executableModule: ResolvedTarget {
38-
precondition(type == .executable || type == .snippet, "This property should only be called for executable targets")
38+
public func executableTarget() throws -> ResolvedTarget {
39+
guard type == .executable || type == .snippet else {
40+
throw InternalError("firstExecutableModule should only be called for executable targets")
41+
}
3942
return targets.first(where: { $0.type == .executable || $0.type == .snippet })!
4043
}
4144

Sources/PackageLoading/ManifestLoader.swift

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ public final class ManifestLoader: ManifestLoaderProtocol {
278278
var targets = parsedManifest.targets
279279
if products.isEmpty, targets.isEmpty,
280280
fileSystem.isFile(path.parentDirectory.appending(component: moduleMapFilename)) {
281-
products.append(ProductDescription(
281+
try products.append(ProductDescription(
282282
name: parsedManifest.name,
283283
type: .library(.automatic),
284284
targets: [parsedManifest.name])
@@ -524,7 +524,9 @@ public final class ManifestLoader: ManifestLoaderProtocol {
524524
}
525525

526526
// We should not have any fatal error at this point.
527-
assert(result.errorOutput == nil)
527+
guard result.errorOutput == nil else {
528+
throw InternalError("unexpected error output: \(result.errorOutput!)")
529+
}
528530

529531
// We might have some non-fatal output (warnings/notes) from the compiler even when
530532
// we were able to parse the manifest successfully.
@@ -802,17 +804,18 @@ public final class ManifestLoader: ManifestLoaderProtocol {
802804
delegateQueue: DispatchQueue,
803805
completion: @escaping (Result<EvaluationResult, Error>) -> Void
804806
) {
807+
// The compiler has special meaning for files with extensions like .ll, .bc etc.
808+
// Assert that we only try to load files with extension .swift to avoid unexpected loading behavior.
809+
guard manifestPath.extension == "swift" else {
810+
return completion(.failure(InternalError("Manifest files must contain .swift suffix in their name, given: \(manifestPath).")))
811+
}
812+
805813
var evaluationResult = EvaluationResult()
806814

807815
delegateQueue.async {
808816
self.delegate?.willParse(manifest: manifestPath)
809817
}
810818

811-
// The compiler has special meaning for files with extensions like .ll, .bc etc.
812-
// Assert that we only try to load files with extension .swift to avoid unexpected loading behavior.
813-
assert(manifestPath.extension == "swift",
814-
"Manifest files must contain .swift suffix in their name, given: \(manifestPath).")
815-
816819
// For now, we load the manifest by having Swift interpret it directly.
817820
// Eventually, we should have two loading processes, one that loads only
818821
// the declarative package specification using the Swift compiler directly

Sources/PackageLoading/PackageBuilder.swift

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -889,7 +889,7 @@ public final class PackageBuilder {
889889
moduleMapType = .none
890890
}
891891

892-
return ClangTarget(
892+
return try ClangTarget(
893893
name: potentialModule.name,
894894
bundleName: bundleName,
895895
defaultLocalization: manifest.defaultLocalization,
@@ -1127,7 +1127,9 @@ public final class PackageBuilder {
11271127
}
11281128

11291129
while true {
1130-
assert(searchPath.isDescendantOfOrEqual(to: packagePath), "search path \(searchPath) is outside the package \(packagePath)")
1130+
guard searchPath.isDescendantOfOrEqual(to: packagePath) else {
1131+
throw InternalError("search path \(searchPath) is outside the package \(packagePath)")
1132+
}
11311133
// If we have already searched this path, skip.
11321134
if !pathsSearched.contains(searchPath) {
11331135
SwiftTarget.testManifestNames.forEach { name in
@@ -1181,7 +1183,7 @@ public final class PackageBuilder {
11811183
// If enabled, create one test product for each test target.
11821184
if self.shouldCreateMultipleTestProducts {
11831185
for testTarget in testModules {
1184-
let product = Product(name: testTarget.name, type: .test, targets: [testTarget])
1186+
let product = try Product(name: testTarget.name, type: .test, targets: [testTarget])
11851187
append(product)
11861188
}
11871189
} else if !testModules.isEmpty {
@@ -1194,7 +1196,7 @@ public final class PackageBuilder {
11941196
let productName = self.manifest.displayName + "PackageTests"
11951197
let testManifest = try self.findTestManifest(in: testModules)
11961198

1197-
let product = Product(name: productName, type: .test, targets: testModules, testManifest: testManifest)
1199+
let product = try Product(name: productName, type: .test, targets: testModules, testManifest: testManifest)
11981200
append(product)
11991201
}
12001202

@@ -1247,7 +1249,7 @@ public final class PackageBuilder {
12471249
}
12481250
}
12491251

1250-
append(Product(name: product.name, type: product.type, targets: targets))
1252+
try append(Product(name: product.name, type: product.type, targets: targets))
12511253
}
12521254

12531255
// Add implicit executables - for root packages and for dependency plugins.
@@ -1291,7 +1293,7 @@ public final class PackageBuilder {
12911293
} else {
12921294
if self.manifest.packageKind.isRoot || implicitPlugInExecutables.contains(target.name) {
12931295
// Generate an implicit product for the executable target
1294-
let product = Product(name: target.name, type: .executable, targets: [target])
1296+
let product = try Product(name: target.name, type: .executable, targets: [target])
12951297
append(product)
12961298
}
12971299
}
@@ -1304,7 +1306,7 @@ public final class PackageBuilder {
13041306
if libraryTargets.isEmpty {
13051307
self.observabilityScope.emit(.noLibraryTargetsForREPL)
13061308
} else {
1307-
let replProduct = Product(
1309+
let replProduct = try Product(
13081310
name: self.identity.description + Product.replProductSuffix,
13091311
type: .library(.dynamic),
13101312
targets: libraryTargets
@@ -1314,9 +1316,9 @@ public final class PackageBuilder {
13141316
}
13151317

13161318
// Create implicit snippet products
1317-
targets
1319+
try targets
13181320
.filter { $0.type == .snippet }
1319-
.map { Product(name: $0.name, type: .snippet, targets: [$0]) }
1321+
.map { try Product(name: $0.name, type: .snippet, targets: [$0]) }
13201322
.forEach(append)
13211323

13221324
return products.map{ $0.item }
@@ -1357,7 +1359,6 @@ public final class PackageBuilder {
13571359

13581360
/// We create this structure after scanning the filesystem for potential targets.
13591361
private struct PotentialModule: Hashable {
1360-
13611362
/// Name of the target.
13621363
let name: String
13631364

@@ -1371,16 +1372,6 @@ private struct PotentialModule: Hashable {
13711372

13721373
/// The target type.
13731374
let type: TargetDescription.TargetType
1374-
1375-
/// The base prefix for the test target, used to associate with the target it tests.
1376-
public var basename: String {
1377-
guard isTest else {
1378-
fatalError("\(Swift.type(of: self)) should be a test target to access basename.")
1379-
}
1380-
precondition(name.hasSuffix(Target.testModuleNameSuffix))
1381-
let endIndex = name.index(name.endIndex, offsetBy: -Target.testModuleNameSuffix.count)
1382-
return String(name[name.startIndex..<endIndex])
1383-
}
13841375
}
13851376

13861377
private extension Manifest {

Sources/PackageLoading/PkgConfig.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public struct PkgConfig {
8080
)
8181
}
8282

83-
var parser = PkgConfigParser(pcFile: pcFile, fileSystem: fileSystem)
83+
var parser = try PkgConfigParser(pcFile: pcFile, fileSystem: fileSystem)
8484
try parser.parse()
8585

8686
func getFlags(from dependencies: [String]) throws -> (cFlags: [String], libs: [String]) {
@@ -152,8 +152,10 @@ internal struct PkgConfigParser {
152152
public private(set) var cFlags = [String]()
153153
public private(set) var libs = [String]()
154154

155-
public init(pcFile: AbsolutePath, fileSystem: FileSystem) {
156-
precondition(fileSystem.isFile(pcFile))
155+
public init(pcFile: AbsolutePath, fileSystem: FileSystem) throws {
156+
guard fileSystem.isFile(pcFile) else {
157+
throw StringError("invalid pcfile \(pcFile)")
158+
}
157159
self.pcFile = pcFile
158160
self.fileSystem = fileSystem
159161
}
@@ -195,7 +197,9 @@ internal struct PkgConfigParser {
195197
}
196198

197199
private mutating func parseKeyValue(line: String) throws {
198-
precondition(line.contains(":"))
200+
guard line.contains(":") else {
201+
throw InternalError("invalid pcfile, expecting line to contain :")
202+
}
199203
let (key, maybeValue) = line.spm_split(around: ":")
200204
let value = try resolveVariables(maybeValue?.spm_chuzzle() ?? "")
201205
switch key {

Sources/PackageModel/Manifest/ProductDescription.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
99
*/
1010

11+
import Basics
12+
1113
/// The product description
1214
public struct ProductDescription: Equatable, Codable {
1315

@@ -24,8 +26,10 @@ public struct ProductDescription: Equatable, Codable {
2426
name: String,
2527
type: ProductType,
2628
targets: [String]
27-
) {
28-
precondition(type != .test, "Declaring test products isn't supported: \(name):\(targets)")
29+
) throws {
30+
guard type != .test else {
31+
throw InternalError("Declaring test products isn't supported: \(name):\(targets)")
32+
}
2933
self.name = name
3034
self.type = type
3135
self.targets = targets

Sources/PackageModel/Product.swift

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
99
*/
1010

11+
import Basics
1112
import TSCBasic
1213

1314
import struct TSCUtility.PolymorphicCodableArray
@@ -32,14 +33,19 @@ public class Product: Codable {
3233
/// The suffix for REPL product name.
3334
public static let replProductSuffix: String = "__REPL"
3435

35-
public init(name: String, type: ProductType, targets: [Target], testManifest: AbsolutePath? = nil) {
36-
precondition(!targets.isEmpty)
36+
public init(name: String, type: ProductType, targets: [Target], testManifest: AbsolutePath? = nil) throws {
37+
guard !targets.isEmpty else {
38+
throw InternalError("Targets cannot be empty")
39+
}
3740
if type == .executable {
38-
assert(targets.filter({ $0.type == .executable }).count == 1,
39-
"Executable products should have exactly one executable target.")
41+
guard targets.filter({ $0.type == .executable }).count == 1 else {
42+
throw InternalError("Executable products should have exactly one executable target.")
43+
}
4044
}
4145
if testManifest != nil {
42-
assert(type == .test, "Test manifest should only be set on test products")
46+
guard type == .test else {
47+
throw InternalError("Test manifest should only be set on test products")
48+
}
4349
}
4450
self.name = name
4551
self.type = type

0 commit comments

Comments
 (0)