Skip to content

Commit 65110a4

Browse files
committed
Add ToolsVersion flag for experiementalMultiLang
1 parent 8ca6c7d commit 65110a4

File tree

7 files changed

+57
-10
lines changed

7 files changed

+57
-10
lines changed

Sources/PackageLoading/TargetSourcesBuilder.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,12 @@ public struct TargetSourcesBuilder {
220220
try diagnoseInfoPlistConflicts(in: resources)
221221
diagnoseInvalidResource(in: target.resources)
222222

223+
// It's an error to contain mixed language source files
224+
// Unless experimental flag is turned on
225+
if sources.containsMixedLanguage && !toolsVersion.experimentalMultiLang {
226+
throw Module.Error.mixedSources(targetPath)
227+
}
228+
223229
return (sources, resources, headers, ignored, others)
224230
}
225231

Sources/PackageLoading/ToolsVersionParser.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -358,12 +358,12 @@ public struct ToolsVersionParser {
358358
/// - Note: For a misspelt Swift tools version specification `"// swift-too1s-version:5.3"`, the first `"1"` is considered as the first character of the version specifier, and so `"1s-version:5.3"` is taken as the version specifier.
359359
let versionSpecifier = specificationSnippetFromLabelToLineTerminator[startIndexOfVersionSpecifier..<indexOfVersionSpecifierTerminator]
360360

361-
/// Look for experimental features. They are space separated values contained in parenthases right after the ";", e.g. "// swift-tools-version: 6.3;(experimentalCGen)"
361+
/// Look for experimental features. They are comma separated values contained in parenthases right after the ";", e.g. "// swift-tools-version: 6.4;(experimentalCGen,experimentalMultiLang)"
362362
var experimentalFeatures: Set<ToolsVersion.ExperimentalFeature> = []
363363
if indexOfVersionSpecifierTerminator < specificationWithIgnoredTrailingContents.endIndex, specificationWithIgnoredTrailingContents[indexOfVersionSpecifierTerminator...].hasPrefix(";(") {
364364
let startOfExperimentalFeatures = specificationWithIgnoredTrailingContents.index(indexOfVersionSpecifierTerminator, offsetBy: 2)
365365
if let endOfExperimentalFeatures = specificationWithIgnoredTrailingContents[startOfExperimentalFeatures...].firstIndex(where: { $0 == ")" }) {
366-
for featureString in specificationWithIgnoredTrailingContents[startOfExperimentalFeatures..<endOfExperimentalFeatures].split(separator: " ", omittingEmptySubsequences: true) {
366+
for featureString in specificationWithIgnoredTrailingContents[startOfExperimentalFeatures..<endOfExperimentalFeatures].split(separator: ",", omittingEmptySubsequences: true) {
367367
if let feature = ToolsVersion.ExperimentalFeature(rawValue: String(featureString)) {
368368
experimentalFeatures.insert(feature)
369369
}

Sources/PackageModel/ToolsVersion.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ public struct ToolsVersion: Equatable, Hashable, Codable, Sendable {
9090
/// Experimental features
9191
public enum ExperimentalFeature: String, Sendable, Codable {
9292
case experimentalCGen
93+
case experimentalMultiLang
9394
}
9495
public let experimentalFeatures: Set<ExperimentalFeature>?
9596

@@ -104,6 +105,10 @@ public struct ToolsVersion: Equatable, Hashable, Codable, Sendable {
104105
self >= .v6_3 && experimentalFeatures?.contains(.experimentalCGen) == true
105106
}
106107

108+
public var experimentalMultiLang: Bool {
109+
self >= .v6_4 && experimentalFeatures?.contains(.experimentalMultiLang) == true
110+
}
111+
107112
/// Create an instance of tools version from a given string.
108113
public init?(string: String, experimentalFeatures: Set<ExperimentalFeature>) {
109114
guard let match = ToolsVersion.toolsVersionRegex.firstMatch(

Tests/PackageLoadingTests/PackageBuilderTests.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ struct PackageBuilderTests {
7878
let manifest = Manifest.createRootManifest(
7979
displayName: "pkg",
8080
path: .root,
81+
toolsVersion: try #require(ToolsVersion(string: "6.4.0", experimentalFeatures: [.experimentalMultiLang])),
8182
targets: [
8283
try TargetDescription(name: "foo"),
8384
]
@@ -97,6 +98,27 @@ struct PackageBuilderTests {
9798
}
9899
}
99100

101+
@Test
102+
func testMixedSourcesDisabled() throws {
103+
let foo: AbsolutePath = "/Sources/foo"
104+
105+
let fs = InMemoryFileSystem(emptyFiles:
106+
foo.appending(components: "Foo.swift").pathString,
107+
foo.appending(components: "CFoo.c").pathString
108+
)
109+
110+
let manifest = Manifest.createRootManifest(
111+
displayName: "pkg",
112+
path: .root,
113+
targets: [
114+
try TargetDescription(name: "foo"),
115+
]
116+
)
117+
try PackageBuilderTester(manifest, in: fs) { package, diagnostics in
118+
diagnostics.check(diagnostic: "target at '\(foo)' contains mixed language source files; feature not supported", severity: .error)
119+
}
120+
}
121+
100122
@Test
101123
func testBrokenSymlink() throws {
102124
try testWithTemporaryDirectory { path in

Tests/PackageLoadingTests/ToolsVersionParserTests.swift

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -838,13 +838,24 @@ final class ToolsVersionParserTests: XCTestCase {
838838
XCTAssertEqual(version.description, "5.0.0")
839839
}
840840

841-
func testExperimentalFlag() throws {
842-
let version = try ToolsVersionParser.parse(utf8String: "// swift-tools-version: 6.3;(experimentalCGen)")
843-
XCTAssertEqual(version, ToolsVersion(version: .init(6, 3, 0)))
844-
XCTAssertTrue(version.experimentalFeatures?.contains(.experimentalCGen) == true)
845-
846-
let version2 = try ToolsVersionParser.parse(utf8String: "// swift-tools-version: 6.3;(experimentalIgnored)")
847-
XCTAssertEqual(version2, ToolsVersion(version: .init(6, 3, 0)))
848-
XCTAssertNil(version2.experimentalFeatures)
841+
func testExperimentalFlags() throws {
842+
let cgen = try ToolsVersionParser.parse(utf8String: "// swift-tools-version: 6.3;(experimentalCGen)")
843+
XCTAssertEqual(cgen, ToolsVersion(version: .init(6, 3, 0)))
844+
XCTAssertTrue(cgen.experimentalFeatures?.contains(.experimentalCGen) == true)
845+
XCTAssertTrue(cgen.experimentalFeatures?.contains(.experimentalMultiLang) ?? false == false)
846+
847+
let multiLang = try ToolsVersionParser.parse(utf8String: "// swift-tools-version: 6.4;(experimentalMultiLang)")
848+
XCTAssertEqual(multiLang, ToolsVersion(version: .init(6, 4, 0)))
849+
XCTAssertTrue(multiLang.experimentalFeatures?.contains(.experimentalMultiLang) == true)
850+
XCTAssertTrue(multiLang.experimentalFeatures?.contains(.experimentalCGen) ?? false == false)
851+
852+
let both = try ToolsVersionParser.parse(utf8String: "// swift-tools-version: 6.4;(experimentalCGen,experimentalMultiLang)")
853+
XCTAssertEqual(both, ToolsVersion(version: .init(6, 4, 0)))
854+
XCTAssertTrue(both.experimentalFeatures?.contains(.experimentalMultiLang) == true)
855+
XCTAssertTrue(both.experimentalFeatures?.contains(.experimentalCGen) == true)
856+
857+
let invalid = try ToolsVersionParser.parse(utf8String: "// swift-tools-version: 6.3;(experimentalIgnored)")
858+
XCTAssertEqual(invalid, ToolsVersion(version: .init(6, 3, 0)))
859+
XCTAssertNil(invalid.experimentalFeatures)
849860
}
850861
}

Tests/PackageModelTests/ToolsVersionTests.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
1010
//
1111
//===----------------------------------------------------------------------===//
12+
1213
import Foundation
14+
import PackageLoading
1315
import PackageModel
1416
import Testing
1517

Tests/SwiftBuildSupportTests/PIFBuilderTests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,6 +1039,7 @@ struct PIFBuilderTests {
10391039
Manifest.createRootManifest(
10401040
displayName: "Pkg",
10411041
path: "/Pkg",
1042+
toolsVersion: try #require(ToolsVersion(string: "6.4.0", experimentalFeatures: [.experimentalMultiLang])),
10421043
targets: [
10431044
TargetDescription(name: "lib"),
10441045
]

0 commit comments

Comments
 (0)