diff --git a/metadata-generator/CMakeLists.txt b/metadata-generator/CMakeLists.txt index 4ae9950df..bc57c05a8 100644 --- a/metadata-generator/CMakeLists.txt +++ b/metadata-generator/CMakeLists.txt @@ -69,5 +69,8 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) add_subdirectory(src) + +enable_testing() +add_subdirectory(tests) # copy build-step-metadata-generator.py to the bin folder configure_file(build-step-metadata-generator.py ${CMAKE_CURRENT_BINARY_DIR}/bin/build-step-metadata-generator.py COPYONLY) diff --git a/metadata-generator/README.md b/metadata-generator/README.md index 899608a63..b0ee3f57a 100644 --- a/metadata-generator/README.md +++ b/metadata-generator/README.md @@ -46,3 +46,112 @@ Example command line arguments: ``` For a better way of generating these arguments, just run the TestRunner scheme on the v8ios-runtime project and get the arguments from the log. + +## Swift (Symbol Graph) support + +The generator can import Swift modules from symbol graphs (`*.symbols.json`, as +written by `swiftc -emit-symbol-graph` or `swift symbolgraph-extract`). Graphs +are loaded structurally into a Swift-specific IR (`src/Swift/SwiftIR.h`): every +public declaration with its precise USR, kind, access level, parameters and +labels, effects (`async`/`throws`), settability, generics, availability, +extension info, and resolved relationships (members, conformances, superclass, +overrides, protocol requirements). Malformed or unexpected input is reported as +diagnostics with stable codes (`invalid-json`, `unsupported-format-version`, +`duplicate-symbol`, `parameter-label-mismatch`, ...); errors make the generator +exit non-zero. + +`--swift-thunk-output ` writes `+NativeScript.swift`: a Swift +thunk for every declaration the runtime can call, plus the +`ns_swift_register_` function the runtime looks up. `-output-typescript` +writes `swift!.d.ts`, declaring exactly that surface as the +`ns:swift/` module. Both come from the same registration model +(`src/Swift/SwiftSurface.h`). See `docs/swift-interop.md` for the app-side +workflow and the JavaScript semantics. + +### Capability classification and coverage + +Every declaration is classified into one tier, with machine-readable reasons +for anything not generated (`src/Swift/CapabilityClassifier.h` lists the +codes): + +| Tier | Meaning | +|---|---| +| `objc-direct` | Objective-C-visible (`c:` USR); served by the existing metadata runtime | +| `swift-generated` | callable through a generated Swift thunk | +| `swift-specialized` | needs an explicit generic specialization first | +| `type-only` | representable in TypeScript, not callable (protocols, type aliases) | +| `unsupported` | not bridgeable yet; `reasons` say why | +| `not-applicable` | not an API surface (deinitializers, macros) | + +The generated surface currently bridges `Bool`, integer and floating-point +types, `String`, optionals of those, module classes and actors (handles), +module structs (boxed copies) and payload-less enums (case-name strings). + +`--swift-coverage-output ` writes `.coverage.json`: counts per +tier and kind, a histogram of reasons, and every symbol's classification. +`effectiveCallable` counts what is callable through either the Objective-C +runtime or a thunk. + +### Compiler verification + +Symbol graphs do not carry every fact a call needs (e.g. `~Copyable` is often +invisible), so the generated surface can be checked by the Swift compiler. +`--swift-probe-output ` writes `.probe.swift`, which calls every +generated declaration the way a thunk will, and a line map back to symbols. +`--swift-verify` type-checks those probes, demotes every declaration the +compiler rejects (`compiler-rejected:`), and repeats until the probes +type-check: + +``` +./objc-metadata-generator --skip-objc \ + --swift-symbolgraph-dir \ + --swift-deployment-target 15.0 \ + --swift-verify \ + --swift-sdk "$(xcrun --sdk iphonesimulator --show-sdk-path)" \ + --swift-target arm64-apple-ios15.0-simulator \ + --swift-search-path \ + --swift-coverage-output +``` + +`--swift-deployment-target` sets the version availability decisions are made +against; it defaults to the minimum version recorded in the graphs, which +`swift-symbolgraph-extract` sets to the SDK version. + +``` +./objc-metadata-generator \ + -output-typescript \ + --swift-symbolgraph-dir /symbolgraphs \ + --swift-ir-output \ + --skip-objc +``` + +- `--swift-symbolgraph-dir` – directory searched recursively for symbol graphs +- `--swift-ir-output` – optional; writes `.swift-ir.json`, a deterministic dump of the IR +- `--skip-objc` – skip the Objective-C phase + +Environment variables (if using build-step script): +- `NS_SWIFT_SYMBOLGRAPH_DIR` (or `TNS_SWIFT_SYMBOLGRAPH_DIR`) – path to symbol graph directory +- `NS_SKIP_OBJC_METADATA` (or `TNS_SKIP_OBJC_METADATA`) – set to `1` to skip Objective-C phase + +### Tests + +`swift-symbolgraph-tests` is built alongside the generator and runs against the +checked-in graphs in `TestFixtures/SwiftDemo/symbolgraphs`, so it needs no Swift +toolchain: + +``` +cmake --build build --target swift-symbolgraph-tests +./build/bin/swift-symbolgraph-tests # or: (cd build && ctest) +./build/bin/swift-symbolgraph-tests Snapshot # run tests whose name contains "Snapshot" +``` + +The snapshot tests (`IRSnapshot`, `TypeScriptSnapshot`, `CoverageSnapshot`, +`ProbeSnapshot`) compare against `tests/swift/snapshots/`; +`ThunkSourceMatchesFixtureInterop` keeps +`TestFixtures/SwiftDemo/Interop/SwiftDemo+NativeScript.swift`, which TestRunner +compiles, identical to the generator's output. `TypeScriptUsageCompiles` runs +`tsc` (from `PATH` or `NS_TSC`) over `tests/swift/typescript/usage.ts`. `ProbesTypeCheck` +and the `Verifier*` tests build the fixture module and run the Swift compiler; +they are skipped when `xcrun` is unavailable. After an intended output change, regenerate them with +`NS_UPDATE_SNAPSHOTS=1 ./build/bin/swift-symbolgraph-tests` and review +the diff. diff --git a/metadata-generator/TestFixtures/SwiftDemo/.gitignore b/metadata-generator/TestFixtures/SwiftDemo/.gitignore new file mode 100644 index 000000000..14dfef462 --- /dev/null +++ b/metadata-generator/TestFixtures/SwiftDemo/.gitignore @@ -0,0 +1,23 @@ +# SwiftPM build artifacts +.build/ +.swiftpm/ + +# Generated symbol graphs, except the checked-in corpus the loader tests read +.symbolgraph/ +*.symbolgraph +*.symbols.json +!symbolgraphs/*.symbols.json + +# Swift package resolution (optional to commit; ignore for test fixture) +Package.resolved + +# macOS noise +.DS_Store + +# Editor/IDE +.vscode/ +.idea/ + +# Deprecated Xcode project generation artifacts +*.xcodeproj/ +*.xcworkspace/ diff --git a/metadata-generator/TestFixtures/SwiftDemo/Interop/SwiftDemo+NativeScript.swift b/metadata-generator/TestFixtures/SwiftDemo/Interop/SwiftDemo+NativeScript.swift new file mode 100644 index 000000000..6a94315e5 --- /dev/null +++ b/metadata-generator/TestFixtures/SwiftDemo/Interop/SwiftDemo+NativeScript.swift @@ -0,0 +1,712 @@ +// Generated by objc-metadata-generator from the SwiftDemo symbol graphs. Do not edit. +// NativeScript Swift interop thunks, ABI 1: see NativeScript/runtime/SwiftInterop.h. +import Foundation +import SwiftDemo + +private typealias __NSThunk = @convention(c) (UnsafeMutableRawPointer, UnsafeRawPointer?, Int) -> Void +private typealias __NSRelease = @convention(c) (UnsafeMutableRawPointer) -> Void + +private final class __NSBox { + var value: Value + init(_ value: Value) { self.value = value } +} + +// Reads arguments (24-byte slots) and reports results through the runtime's +// API table, whose address is the first word of the call context. +private struct __NSCall { + let call: UnsafeMutableRawPointer + let args: UnsafeRawPointer? + + private func slot(_ index: Int, _: Function.Type) -> Function { + call.load(as: UnsafeRawPointer.self).load(fromByteOffset: index * 8, as: Function.self) + } + + func isNull(_ i: Int) -> Bool { args!.load(fromByteOffset: i * 24, as: UInt32.self) == 0 } + func bool(_ i: Int) -> Bool { args!.load(fromByteOffset: i * 24 + 8, as: UInt8.self) != 0 } + func int64(_ i: Int) -> Int64 { args!.load(fromByteOffset: i * 24 + 8, as: Int64.self) } + func uint64(_ i: Int) -> UInt64 { args!.load(fromByteOffset: i * 24 + 8, as: UInt64.self) } + func double(_ i: Int) -> Double { args!.load(fromByteOffset: i * 24 + 8, as: Double.self) } + func string(_ i: Int) -> String { + let base = args!.load(fromByteOffset: i * 24 + 8, as: UnsafePointer?.self) + let length = Int(args!.load(fromByteOffset: i * 24 + 16, as: UInt64.self)) + return String(decoding: UnsafeBufferPointer(start: base, count: length), as: UTF8.self) + } + func object(_ i: Int) -> AnyObject { + let pointer = args!.load(fromByteOffset: i * 24 + 8, as: UnsafeMutableRawPointer.self) + return Unmanaged.fromOpaque(pointer).takeUnretainedValue() + } + + func returnVoid() { + slot(0, (@convention(c) (UnsafeMutableRawPointer) -> Void).self)(call) + } + func returnBool(_ value: Bool) { + slot(1, (@convention(c) (UnsafeMutableRawPointer, UInt8) -> Void).self)(call, value ? 1 : 0) + } + func returnInt64(_ value: Int64) { + slot(2, (@convention(c) (UnsafeMutableRawPointer, Int64) -> Void).self)(call, value) + } + func returnUInt64(_ value: UInt64) { + slot(3, (@convention(c) (UnsafeMutableRawPointer, UInt64) -> Void).self)(call, value) + } + func returnDouble(_ value: Double) { + slot(4, (@convention(c) (UnsafeMutableRawPointer, Double) -> Void).self)(call, value) + } + func returnString(_ value: String) { + var value = value + value.withUTF8 { + slot(5, (@convention(c) (UnsafeMutableRawPointer, UnsafePointer?, Int) -> Void).self)( + call, $0.baseAddress, $0.count) + } + } + func returnNull() { + slot(6, (@convention(c) (UnsafeMutableRawPointer) -> Void).self)(call) + } + func returnObject(_ object: AnyObject, _ typeIndex: UInt32) { + slot(7, (@convention(c) (UnsafeMutableRawPointer, UnsafeMutableRawPointer, UInt32) -> Void).self)( + call, Unmanaged.passRetained(object).toOpaque(), typeIndex) + } + func throwError(_ error: any Error) { + report(String(describing: error), String(reflecting: type(of: error))) + } + func throwMessage(_ message: String) { + report(message, "") + } + func throwTypeError(_ message: String) { + var message = message + message.withUTF8 { + slot(9, (@convention(c) (UnsafeMutableRawPointer, UnsafePointer?, Int) -> Void).self)( + call, $0.baseAddress, $0.count) + } + } + private func report(_ message: String, _ type: String) { + var message = message + var type = type + message.withUTF8 { messageBytes in + type.withUTF8 { typeBytes in + slot(8, (@convention(c) (UnsafeMutableRawPointer, UnsafePointer?, Int, + UnsafePointer?, Int) -> Void).self)( + call, messageBytes.baseAddress, messageBytes.count, typeBytes.baseAddress, typeBytes.count) + } + } + } +} + +private func __nsRelease(_ object: UnsafeMutableRawPointer) { + Unmanaged.fromOpaque(object).release() +} + +private func __nsEnum1(_ name: String) -> SwiftDemo.Precipitation? { + switch name { + case "rain": return SwiftDemo.Precipitation.`rain` + case "snow": return SwiftDemo.Precipitation.`snow` + case "none": return SwiftDemo.Precipitation.`none` + default: return nil + } +} + +private func __nsEnumName1(_ value: SwiftDemo.Precipitation) -> String { + switch value { + case SwiftDemo.Precipitation.`rain`: return "rain" + case SwiftDemo.Precipitation.`snow`: return "snow" + case SwiftDemo.Precipitation.`none`: return "none" + @unknown default: return String(describing: value) + } +} + +private func __nsEnum5(_ name: String) -> SwiftDemo.Flavor? { + switch name { + case "vanilla": return SwiftDemo.Flavor.`vanilla` + case "chocolate": return SwiftDemo.Flavor.`chocolate` + default: return nil + } +} + +private func __nsEnumName5(_ value: SwiftDemo.Flavor) -> String { + switch value { + case SwiftDemo.Flavor.`vanilla`: return "vanilla" + case SwiftDemo.Flavor.`chocolate`: return "chocolate" + @unknown default: return String(describing: value) + } +} + +private func __nsTypeIndex(_ object: AnyObject, _ declared: UInt32) -> UInt32 { + if object is SwiftDemo.Square { return 7 } + return declared +} + +// s:9SwiftDemo0B0C5greet4name5timesS2S_SitF +private func __nsThunk0(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let receiver = rt.object(0) as? SwiftDemo.Demo else { return rt.throwTypeError("receiver must be SwiftDemo.Demo") } + let a0 = rt.string(1) + let a1 = Int(truncatingIfNeeded: rt.int64(2)) + let result: String = receiver.`greet`(name: a0, times: a1) + rt.returnString(result) +} + +// s:9SwiftDemo0B0C5greet4nameS2S_tF +private func __nsThunk1(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let receiver = rt.object(0) as? SwiftDemo.Demo else { return rt.throwTypeError("receiver must be SwiftDemo.Demo") } + let a0 = rt.string(1) + let result: String = receiver.`greet`(name: a0) + rt.returnString(result) +} + +// s:9SwiftDemo0B0C7versionSSvpZ +private func __nsThunk2(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let result: String = SwiftDemo.Demo.`version` + rt.returnString(result) +} + +// s:9SwiftDemo0B0CACycfc +private func __nsThunk3(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let result: SwiftDemo.Demo = SwiftDemo.Demo() + rt.returnObject(result, __nsTypeIndex(result, 0)) +} + +// s:9SwiftDemo10echoUInt64ys0D0VADF +private func __nsThunk4(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let a0 = rt.uint64(0) + let result: UInt64 = SwiftDemo.`echoUInt64`(a0) + rt.returnUInt64(UInt64(result)) +} + +// s:9SwiftDemo10largestIntSiyF +private func __nsThunk5(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let result: Int = SwiftDemo.`largestInt`() + rt.returnInt64(Int64(result)) +} + +// s:9SwiftDemo11checkedSideyS2dKF +private func __nsThunk6(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let a0 = rt.double(0) + do { + let result: Double = try SwiftDemo.`checkedSide`(a0) + rt.returnDouble(Double(result)) + } catch { + rt.throwError(error) + } +} + +// s:9SwiftDemo13PrecipitationO8rawValueACSgSS_tcfc +private func __nsThunk7(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let a0 = rt.string(0) + let result: SwiftDemo.Precipitation? = SwiftDemo.Precipitation(rawValue: a0) + if let result { + rt.returnString(__nsEnumName1(result)) + } else { + rt.returnNull() + } +} + +// s:9SwiftDemo13defaultFlavorAA0D0Ovp +private func __nsThunk8(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let result: SwiftDemo.Flavor = SwiftDemo.`defaultFlavor` + rt.returnString(__nsEnumName5(result)) +} + +// s:9SwiftDemo13globalCounterSivp +private func __nsThunk9(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let result: Int = SwiftDemo.`globalCounter` + rt.returnInt64(Int64(result)) +} + +// s:9SwiftDemo13globalCounterSivp (setter) +private func __nsThunk10(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let newValue = Int(truncatingIfNeeded: rt.int64(0)) + SwiftDemo.`globalCounter` = newValue + rt.returnVoid() +} + +// s:9SwiftDemo16makeDefaultPointAA0E0VyF +private func __nsThunk11(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let result: SwiftDemo.Point = SwiftDemo.`makeDefaultPoint`() + rt.returnObject(__NSBox(result), 3) +} + +// s:9SwiftDemo4RingV5inner5outerAcA5PointV_AGtcfc +private func __nsThunk12(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let a0 = (rt.object(0) as? __NSBox)?.value else { return rt.throwTypeError("argument 1 must be SwiftDemo.Point") } + guard let a1 = (rt.object(1) as? __NSBox)?.value else { return rt.throwTypeError("argument 2 must be SwiftDemo.Point") } + let result: SwiftDemo.Ring = SwiftDemo.Ring(inner: a0, outer: a1) + rt.returnObject(__NSBox(result), 2) +} + +// s:9SwiftDemo4RingV5innerAA5PointVvp +private func __nsThunk13(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let box = rt.object(0) as? __NSBox else { return rt.throwTypeError("receiver must be SwiftDemo.Ring") } + let result: SwiftDemo.Point = box.value.`inner` + rt.returnObject(__NSBox(result), 3) +} + +// s:9SwiftDemo4RingV5innerAA5PointVvp (setter) +private func __nsThunk14(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let box = rt.object(0) as? __NSBox else { return rt.throwTypeError("receiver must be SwiftDemo.Ring") } + guard let newValue = (rt.object(1) as? __NSBox)?.value else { return rt.throwTypeError("value must be SwiftDemo.Point") } + box.value.`inner` = newValue + rt.returnVoid() +} + +// s:9SwiftDemo4RingV5outerAA5PointVvp +private func __nsThunk15(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let box = rt.object(0) as? __NSBox else { return rt.throwTypeError("receiver must be SwiftDemo.Ring") } + let result: SwiftDemo.Point = box.value.`outer` + rt.returnObject(__NSBox(result), 3) +} + +// s:9SwiftDemo4RingV5outerAA5PointVvp (setter) +private func __nsThunk16(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let box = rt.object(0) as? __NSBox else { return rt.throwTypeError("receiver must be SwiftDemo.Ring") } + guard let newValue = (rt.object(1) as? __NSBox)?.value else { return rt.throwTypeError("value must be SwiftDemo.Point") } + box.value.`outer` = newValue + rt.returnVoid() +} + +// s:9SwiftDemo4RingV6expand2byySd_tF +private func __nsThunk17(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let box = rt.object(0) as? __NSBox else { return rt.throwTypeError("receiver must be SwiftDemo.Ring") } + let a0 = rt.double(1) + let _: Void = box.value.`expand`(by: a0) + rt.returnVoid() +} + +// s:9SwiftDemo5PointV11descriptionSSvp +private func __nsThunk18(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let box = rt.object(0) as? __NSBox else { return rt.throwTypeError("receiver must be SwiftDemo.Point") } + let result: String = box.value.`description` + rt.returnString(result) +} + +// s:9SwiftDemo5PointV1x1yACSd_Sdtcfc +private func __nsThunk19(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let a0 = rt.double(0) + let a1 = rt.double(1) + let result: SwiftDemo.Point = SwiftDemo.Point(x: a0, y: a1) + rt.returnObject(__NSBox(result), 3) +} + +// s:9SwiftDemo5PointV1xSdvp +private func __nsThunk20(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let box = rt.object(0) as? __NSBox else { return rt.throwTypeError("receiver must be SwiftDemo.Point") } + let result: Double = box.value.`x` + rt.returnDouble(Double(result)) +} + +// s:9SwiftDemo5PointV1xSdvp (setter) +private func __nsThunk21(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let box = rt.object(0) as? __NSBox else { return rt.throwTypeError("receiver must be SwiftDemo.Point") } + let newValue = rt.double(1) + box.value.`x` = newValue + rt.returnVoid() +} + +// s:9SwiftDemo5PointV1ySdvp +private func __nsThunk22(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let box = rt.object(0) as? __NSBox else { return rt.throwTypeError("receiver must be SwiftDemo.Point") } + let result: Double = box.value.`y` + rt.returnDouble(Double(result)) +} + +// s:9SwiftDemo5PointV1ySdvp (setter) +private func __nsThunk23(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let box = rt.object(0) as? __NSBox else { return rt.throwTypeError("receiver must be SwiftDemo.Point") } + let newValue = rt.double(1) + box.value.`y` = newValue + rt.returnVoid() +} + +// s:9SwiftDemo5PointV6lengthSdvp +private func __nsThunk24(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let box = rt.object(0) as? __NSBox else { return rt.throwTypeError("receiver must be SwiftDemo.Point") } + let result: Double = box.value.`length` + rt.returnDouble(Double(result)) +} + +// s:9SwiftDemo5shoutySSSgACF +private func __nsThunk25(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let a0 = rt.isNull(0) ? nil : rt.string(0) + let result: String? = SwiftDemo.`shout`(a0) + if let result { + rt.returnString(result) + } else { + rt.returnNull() + } +} + +// s:9SwiftDemo6FlavorO11descriptionSSvp +private func __nsThunk26(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let receiver = __nsEnum5(rt.string(0)) else { return rt.throwTypeError("receiver must be SwiftDemo.Flavor") } + let result: String = receiver.`description` + rt.returnString(result) +} + +// s:9SwiftDemo6FlavorO8rawValueACSgSi_tcfc +private func __nsThunk27(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let a0 = Int(truncatingIfNeeded: rt.int64(0)) + let result: SwiftDemo.Flavor? = SwiftDemo.Flavor(rawValue: a0) + if let result { + rt.returnString(__nsEnumName5(result)) + } else { + rt.returnNull() + } +} + +// s:9SwiftDemo6LoaderC10modernOnlyyyF +private func __nsThunk28(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard #available(iOS 16.0, *) else { return rt.throwMessage("modernOnly() requires iOS 16.0") } + guard let receiver = rt.object(0) as? SwiftDemo.Loader else { return rt.throwTypeError("receiver must be SwiftDemo.Loader") } + let _: Void = receiver.`modernOnly`() + rt.returnVoid() +} + +// s:9SwiftDemo6LoaderC11legacyFetchyyF +private func __nsThunk29(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let receiver = rt.object(0) as? SwiftDemo.Loader else { return rt.throwTypeError("receiver must be SwiftDemo.Loader") } + let _: Void = receiver.`legacyFetch`() + rt.returnVoid() +} + +// s:9SwiftDemo6LoaderC8oldFetchyyF +private func __nsThunk30(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let receiver = rt.object(0) as? SwiftDemo.Loader else { return rt.throwTypeError("receiver must be SwiftDemo.Loader") } + let _: Void = receiver.`oldFetch`() + rt.returnVoid() +} + +// s:9SwiftDemo6LoaderCACycfc +private func __nsThunk31(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let result: SwiftDemo.Loader = SwiftDemo.Loader() + rt.returnObject(result, __nsTypeIndex(result, 6)) +} + +// s:9SwiftDemo6SquareC4areaSdvp +private func __nsThunk32(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let receiver = rt.object(0) as? SwiftDemo.Square else { return rt.throwTypeError("receiver must be SwiftDemo.Square") } + let result: Double = receiver.`area` + rt.returnDouble(Double(result)) +} + +// s:9SwiftDemo6SquareC4sideACSd_tcfc +private func __nsThunk33(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let a0 = rt.double(0) + let result: SwiftDemo.Square = SwiftDemo.Square(side: a0) + rt.returnObject(result, __nsTypeIndex(result, 7)) +} + +// s:9SwiftDemo6SquareC4sideSdvp +private func __nsThunk34(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let receiver = rt.object(0) as? SwiftDemo.Square else { return rt.throwTypeError("receiver must be SwiftDemo.Square") } + let result: Double = receiver.`side` + rt.returnDouble(Double(result)) +} + +// s:9SwiftDemo6SquareC4sideSdvp (setter) +private func __nsThunk35(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let receiver = rt.object(0) as? SwiftDemo.Square else { return rt.throwTypeError("receiver must be SwiftDemo.Square") } + let newValue = rt.double(1) + receiver.`side` = newValue + rt.returnVoid() +} + +// s:9SwiftDemo6SquareC5greet4nameS2S_tF +private func __nsThunk36(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let receiver = rt.object(0) as? SwiftDemo.Square else { return rt.throwTypeError("receiver must be SwiftDemo.Square") } + let a0 = rt.string(1) + let result: String = receiver.`greet`(name: a0) + rt.returnString(result) +} + +// s:9SwiftDemo6SquareC5scale2byySd_tF +private func __nsThunk37(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let receiver = rt.object(0) as? SwiftDemo.Square else { return rt.throwTypeError("receiver must be SwiftDemo.Square") } + let a0 = rt.double(1) + let _: Void = receiver.`scale`(by: a0) + rt.returnVoid() +} + +// s:9SwiftDemo6SquareC5sidesSivpZ +private func __nsThunk38(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let result: Int = SwiftDemo.Square.`sides` + rt.returnInt64(Int64(result)) +} + +// s:9SwiftDemo7CounterC5labelSSyF +private func __nsThunk39(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let receiver = rt.object(0) as? SwiftDemo.Counter else { return rt.throwTypeError("receiver must be SwiftDemo.Counter") } + let result: String = receiver.`label`() + rt.returnString(result) +} + +// s:9SwiftDemo7CounterCACycfc +private func __nsThunk40(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let result: SwiftDemo.Counter = SwiftDemo.Counter() + rt.returnObject(result, __nsTypeIndex(result, 8)) +} + +// s:9SwiftDemo7PolygonC11vertexCountSivp +private func __nsThunk41(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let receiver = rt.object(0) as? SwiftDemo.Polygon else { return rt.throwTypeError("receiver must be SwiftDemo.Polygon") } + let result: Int = receiver.`vertexCount` + rt.returnInt64(Int64(result)) +} + +// s:9SwiftDemo7PolygonC4makeACyFZ +private func __nsThunk42(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let result: SwiftDemo.Polygon = SwiftDemo.Polygon.`make`() + rt.returnObject(result, __nsTypeIndex(result, 9)) +} + +// s:9SwiftDemo7PolygonC4name11vertexCountACSS_Sitcfc +private func __nsThunk43(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let a0 = rt.string(0) + let a1 = Int(truncatingIfNeeded: rt.int64(1)) + let result: SwiftDemo.Polygon = SwiftDemo.Polygon(name: a0, vertexCount: a1) + rt.returnObject(result, __nsTypeIndex(result, 9)) +} + +// s:9SwiftDemo7PolygonC4nameACSgSS_tcfc +private func __nsThunk44(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let a0 = rt.string(0) + let result: SwiftDemo.Polygon? = SwiftDemo.Polygon(name: a0) + if let result { + rt.returnObject(result, __nsTypeIndex(result, 9)) + } else { + rt.returnNull() + } +} + +// s:9SwiftDemo7PolygonC4nameSSvp +private func __nsThunk45(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let receiver = rt.object(0) as? SwiftDemo.Polygon else { return rt.throwTypeError("receiver must be SwiftDemo.Polygon") } + let result: String = receiver.`name` + rt.returnString(result) +} + +// s:9SwiftDemo7PolygonC5scale1x1yySd_SdtF +private func __nsThunk46(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let receiver = rt.object(0) as? SwiftDemo.Polygon else { return rt.throwTypeError("receiver must be SwiftDemo.Polygon") } + let a0 = rt.double(1) + let a1 = rt.double(2) + let _: Void = receiver.`scale`(x: a0, y: a1) + rt.returnVoid() +} + +// s:9SwiftDemo7PolygonC5scale2byySd_tF +private func __nsThunk47(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let receiver = rt.object(0) as? SwiftDemo.Polygon else { return rt.throwTypeError("receiver must be SwiftDemo.Polygon") } + let a0 = rt.double(1) + let _: Void = receiver.`scale`(by: a0) + rt.returnVoid() +} + +// s:9SwiftDemo7PolygonC5scale2byySi_tF +private func __nsThunk48(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let receiver = rt.object(0) as? SwiftDemo.Polygon else { return rt.throwTypeError("receiver must be SwiftDemo.Polygon") } + let a0 = Int(truncatingIfNeeded: rt.int64(1)) + let _: Void = receiver.`scale`(by: a0) + rt.returnVoid() +} + +// s:9SwiftDemo7PolygonC6sharedACvpZ +private func __nsThunk49(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let result: SwiftDemo.Polygon = SwiftDemo.Polygon.`shared` + rt.returnObject(result, __nsTypeIndex(result, 9)) +} + +// s:9SwiftDemo7PolygonC8describeySSACSgFZ +private func __nsThunk50(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + var a0: SwiftDemo.Polygon? = nil + if !rt.isNull(0) { + guard let value = rt.object(0) as? SwiftDemo.Polygon else { return rt.throwTypeError("argument 1 must be SwiftDemo.Polygon") } + a0 = value + } + let result: String = SwiftDemo.Polygon.`describe`(a0) + rt.returnString(result) +} + +// s:9SwiftDemo7TrackerC2idACSi_tcfc +private func __nsThunk51(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let a0 = Int(truncatingIfNeeded: rt.int64(0)) + let result: SwiftDemo.Tracker = SwiftDemo.Tracker(id: a0) + rt.returnObject(result, __nsTypeIndex(result, 10)) +} + +// s:9SwiftDemo7TrackerC2idSivp +private func __nsThunk52(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let receiver = rt.object(0) as? SwiftDemo.Tracker else { return rt.throwTypeError("receiver must be SwiftDemo.Tracker") } + let result: Int = receiver.`id` + rt.returnInt64(Int64(result)) +} + +// s:9SwiftDemo7TrackerC4sameACyF +private func __nsThunk53(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let receiver = rt.object(0) as? SwiftDemo.Tracker else { return rt.throwTypeError("receiver must be SwiftDemo.Tracker") } + let result: SwiftDemo.Tracker = receiver.`same`() + rt.returnObject(result, __nsTypeIndex(result, 10)) +} + +// s:9SwiftDemo7TrackerC9liveCountSivpZ +private func __nsThunk54(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let result: Int = SwiftDemo.Tracker.`liveCount` + rt.returnInt64(Int64(result)) +} + +// s:9SwiftDemo8echoInt8ys0D0VADF +private func __nsThunk55(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + let a0 = Int8(truncatingIfNeeded: rt.int64(0)) + let result: Int8 = SwiftDemo.`echoInt8`(a0) + rt.returnInt64(Int64(result)) +} + +// s:SYsSHRzSH8RawValueSYRpzrlE04hashB0Sivp::SYNTHESIZED::s:9SwiftDemo13PrecipitationO +private func __nsThunk56(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let receiver = __nsEnum1(rt.string(0)) else { return rt.throwTypeError("receiver must be SwiftDemo.Precipitation") } + let result: Int = receiver.`hashValue` + rt.returnInt64(Int64(result)) +} + +// s:SYsSHRzSH8RawValueSYRpzrlE04hashB0Sivp::SYNTHESIZED::s:9SwiftDemo6FlavorO +private func __nsThunk57(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ count: Int) { + let rt = __NSCall(call: call, args: args) + guard let receiver = __nsEnum5(rt.string(0)) else { return rt.throwTypeError("receiver must be SwiftDemo.Flavor") } + let result: Int = receiver.`hashValue` + rt.returnInt64(Int64(result)) +} + +#if hasAttribute(c) +@c(ns_swift_register_SwiftDemo) +#else +@_cdecl("ns_swift_register_SwiftDemo") +#endif +public func __nsRegister_SwiftDemo(_ registrar: UnsafeMutableRawPointer) { + let api = registrar.load(as: UnsafeRawPointer.self) + let registerModule = api.load(fromByteOffset: 80, as: (@convention(c) (UnsafeMutableRawPointer, UInt32, UnsafePointer, UnsafePointer, __NSRelease) -> Void).self) + let registerType = api.load(fromByteOffset: 88, as: (@convention(c) (UnsafeMutableRawPointer, UInt32, UInt32, UnsafePointer, UnsafePointer, Int32) -> Void).self) + let registerMember = api.load(fromByteOffset: 96, as: (@convention(c) (UnsafeMutableRawPointer, Int32, UInt32, UInt32, UnsafePointer, UnsafePointer, UnsafePointer, __NSThunk?, __NSThunk?) -> Void).self) + + registerModule(registrar, 1, "SwiftDemo", "619ecd8bdf28f35a", __nsRelease) + registerType(registrar, 0, 0, "Demo", "SwiftDemo.Demo", -1) + registerType(registrar, 1, 3, "Precipitation", "SwiftDemo.Precipitation", -1) + registerType(registrar, 2, 2, "Ring", "SwiftDemo.Ring", -1) + registerType(registrar, 3, 2, "Point", "SwiftDemo.Point", -1) + registerType(registrar, 4, 0, "Canvas", "SwiftDemo.Canvas", -1) + registerType(registrar, 5, 3, "Flavor", "SwiftDemo.Flavor", -1) + registerType(registrar, 6, 0, "Loader", "SwiftDemo.Loader", -1) + registerType(registrar, 7, 0, "Square", "SwiftDemo.Square", 9) + registerType(registrar, 8, 1, "Counter", "SwiftDemo.Counter", -1) + registerType(registrar, 9, 0, "Polygon", "SwiftDemo.Polygon", -1) + registerType(registrar, 10, 0, "Tracker", "SwiftDemo.Tracker", -1) + registerMember(registrar, 0, 1, 0, "greet", "greet(name:times:)", "s,i64>s", __nsThunk0, nil) + registerMember(registrar, 0, 1, 0, "greet", "greet(name:)", "s>s", __nsThunk1, nil) + registerMember(registrar, 0, 4, 0, "version", "version", ">s", __nsThunk2, nil) + registerMember(registrar, 0, 0, 0, "constructor", "init()", ">o0", __nsThunk3, nil) + registerMember(registrar, -1, 5, 0, "echoUInt64", "echoUInt64(_:)", "u64>u64", __nsThunk4, nil) + registerMember(registrar, -1, 5, 0, "largestInt", "largestInt()", ">i64", __nsThunk5, nil) + registerMember(registrar, -1, 5, 1, "checkedSide", "checkedSide(_:)", "f64>f64", __nsThunk6, nil) + registerMember(registrar, 1, 7, 0, "none", "none", ">e1", nil, nil) + registerMember(registrar, 1, 7, 0, "rain", "rain", ">e1", nil, nil) + registerMember(registrar, 1, 7, 0, "snow", "snow", ">e1", nil, nil) + registerMember(registrar, 1, 0, 0, "constructor", "init(rawValue:)", "s>e1?", __nsThunk7, nil) + registerMember(registrar, -1, 6, 0, "defaultFlavor", "defaultFlavor", ">e5", __nsThunk8, nil) + registerMember(registrar, -1, 6, 2, "globalCounter", "globalCounter", ">i64", __nsThunk9, __nsThunk10) + registerMember(registrar, -1, 5, 0, "makeDefaultPoint", "makeDefaultPoint()", ">o3", __nsThunk11, nil) + registerMember(registrar, 2, 0, 0, "constructor", "init(inner:outer:)", "o3,o3>o2", __nsThunk12, nil) + registerMember(registrar, 2, 3, 2, "inner", "inner", ">o3", __nsThunk13, __nsThunk14) + registerMember(registrar, 2, 3, 2, "outer", "outer", ">o3", __nsThunk15, __nsThunk16) + registerMember(registrar, 2, 1, 0, "expand", "expand(by:)", "f64>v", __nsThunk17, nil) + registerMember(registrar, 3, 3, 0, "description", "description", ">s", __nsThunk18, nil) + registerMember(registrar, 3, 0, 0, "constructor", "init(x:y:)", "f64,f64>o3", __nsThunk19, nil) + registerMember(registrar, 3, 3, 2, "x", "x", ">f64", __nsThunk20, __nsThunk21) + registerMember(registrar, 3, 3, 2, "y", "y", ">f64", __nsThunk22, __nsThunk23) + registerMember(registrar, 3, 3, 0, "length", "length", ">f64", __nsThunk24, nil) + registerMember(registrar, -1, 5, 0, "shout", "shout(_:)", "s?>s?", __nsThunk25, nil) + registerMember(registrar, 5, 3, 0, "description", "description", ">s", __nsThunk26, nil) + registerMember(registrar, 5, 7, 0, "vanilla", "vanilla", ">e5", nil, nil) + registerMember(registrar, 5, 0, 0, "constructor", "init(rawValue:)", "i64>e5?", __nsThunk27, nil) + registerMember(registrar, 5, 7, 0, "chocolate", "chocolate", ">e5", nil, nil) + registerMember(registrar, 6, 1, 0, "modernOnly", "modernOnly()", ">v", __nsThunk28, nil) + registerMember(registrar, 6, 1, 0, "legacyFetch", "legacyFetch()", ">v", __nsThunk29, nil) + registerMember(registrar, 6, 1, 0, "oldFetch", "oldFetch()", ">v", __nsThunk30, nil) + registerMember(registrar, 6, 0, 0, "constructor", "init()", ">o6", __nsThunk31, nil) + registerMember(registrar, 7, 3, 0, "area", "area", ">f64", __nsThunk32, nil) + registerMember(registrar, 7, 0, 0, "constructor", "init(side:)", "f64>o7", __nsThunk33, nil) + registerMember(registrar, 7, 3, 2, "side", "side", ">f64", __nsThunk34, __nsThunk35) + registerMember(registrar, 7, 1, 0, "greet", "greet(name:)", "s>s", __nsThunk36, nil) + registerMember(registrar, 7, 1, 0, "scale", "scale(by:)", "f64>v", __nsThunk37, nil) + registerMember(registrar, 7, 4, 0, "sides", "sides", ">i64", __nsThunk38, nil) + registerMember(registrar, 8, 1, 0, "label", "label()", ">s", __nsThunk39, nil) + registerMember(registrar, 8, 0, 0, "constructor", "init()", ">o8", __nsThunk40, nil) + registerMember(registrar, 9, 3, 0, "vertexCount", "vertexCount", ">i64", __nsThunk41, nil) + registerMember(registrar, 9, 2, 0, "make", "make()", ">o9", __nsThunk42, nil) + registerMember(registrar, 9, 0, 0, "constructor", "init(name:vertexCount:)", "s,i64>o9", __nsThunk43, nil) + registerMember(registrar, 9, 0, 0, "constructor", "init(name:)", "s>o9?", __nsThunk44, nil) + registerMember(registrar, 9, 3, 0, "name", "name", ">s", __nsThunk45, nil) + registerMember(registrar, 9, 1, 0, "scale", "scale(x:y:)", "f64,f64>v", __nsThunk46, nil) + registerMember(registrar, 9, 1, 4, "scale", "scale(by:)", "f64>v", __nsThunk47, nil) + registerMember(registrar, 9, 1, 4, "scale", "scale(by:)", "i64>v", __nsThunk48, nil) + registerMember(registrar, 9, 4, 0, "shared", "shared", ">o9", __nsThunk49, nil) + registerMember(registrar, 9, 2, 0, "describe", "describe(_:)", "o9?>s", __nsThunk50, nil) + registerMember(registrar, 10, 0, 0, "constructor", "init(id:)", "i64>o10", __nsThunk51, nil) + registerMember(registrar, 10, 3, 0, "id", "id", ">i64", __nsThunk52, nil) + registerMember(registrar, 10, 1, 0, "same", "same()", ">o10", __nsThunk53, nil) + registerMember(registrar, 10, 4, 0, "liveCount", "liveCount", ">i64", __nsThunk54, nil) + registerMember(registrar, -1, 5, 0, "echoInt8", "echoInt8(_:)", "i8>i8", __nsThunk55, nil) + registerMember(registrar, 1, 3, 0, "hashValue", "hashValue", ">i64", __nsThunk56, nil) + registerMember(registrar, 5, 3, 0, "hashValue", "hashValue", ">i64", __nsThunk57, nil) +} diff --git a/metadata-generator/TestFixtures/SwiftDemo/Package.swift b/metadata-generator/TestFixtures/SwiftDemo/Package.swift new file mode 100644 index 000000000..6ddba2a1e --- /dev/null +++ b/metadata-generator/TestFixtures/SwiftDemo/Package.swift @@ -0,0 +1,17 @@ +// swift-tools-version: 5.9 +import PackageDescription + +let package = Package( + name: "SwiftDemo", + platforms: [ .iOS(.v15) ], + products: [ + .library(name: "SwiftDemo", targets: ["SwiftDemo"]), + // The generated NativeScript thunks, compiled as their own module so + // they reach SwiftDemo only through its public interface. + .library(name: "SwiftDemoInterop", targets: ["SwiftDemoInterop"]), + ], + targets: [ + .target(name: "SwiftDemo", path: "Sources/SwiftDemo"), + .target(name: "SwiftDemoInterop", dependencies: ["SwiftDemo"], path: "Interop"), + ] +) diff --git a/metadata-generator/TestFixtures/SwiftDemo/README.md b/metadata-generator/TestFixtures/SwiftDemo/README.md new file mode 100644 index 000000000..4ad06c1d9 --- /dev/null +++ b/metadata-generator/TestFixtures/SwiftDemo/README.md @@ -0,0 +1,26 @@ +# SwiftDemo fixture + +A Swift package whose declarations cover the shapes the Swift symbol graph +loader must model: classes, structs, enums with raw and associated values, +protocols, actors, `@MainActor` types, nested types, overloads, operators, +subscripts, failable initializers, `async`/`throws`, `inout` and escaping +closure parameters, generics, availability, and extensions of both module and +standard library types. + +`symbolgraphs/` holds the graphs generated from `Sources/`. The loader tests +read these checked-in files, so they run without a Swift toolchain. After +changing `Sources/`, regenerate the graphs and then the test snapshots: + +``` +./generate-symbolgraphs.sh +NS_UPDATE_SNAPSHOTS=1 ../../build/bin/swift-symbolgraph-tests +``` + +Review the resulting snapshot diff before committing it; it is the record of +what the loader extracts. + +`Interop/SwiftDemo+NativeScript.swift` holds the generated thunks (regenerated +by the same `NS_UPDATE_SNAPSHOTS=1` run). TestRunner compiles it with the +fixture sources and exercises it from `TestRunner/app/tests/SwiftInteropTests.js`; +`Package.swift` builds the same files as two SwiftPM modules (`SwiftDemo` and +`SwiftDemoInterop`). diff --git a/metadata-generator/TestFixtures/SwiftDemo/Sources/SwiftDemo/Demo.swift b/metadata-generator/TestFixtures/SwiftDemo/Sources/SwiftDemo/Demo.swift new file mode 100644 index 000000000..bb55705a4 --- /dev/null +++ b/metadata-generator/TestFixtures/SwiftDemo/Sources/SwiftDemo/Demo.swift @@ -0,0 +1,16 @@ +public protocol Greeter { + func greet(name: String) -> String +} + +public class Demo: Greeter { + public init() {} + public func greet(name: String) -> String { "Hello, \(name)" } +} + +public struct Point { + public var x: Double + public var y: Double + public init(x: Double, y: Double) { self.x = x; self.y = y } +} + +public enum Flavor: Int { case vanilla = 0, chocolate = 1 } diff --git a/metadata-generator/TestFixtures/SwiftDemo/Sources/SwiftDemo/Extensions.swift b/metadata-generator/TestFixtures/SwiftDemo/Sources/SwiftDemo/Extensions.swift new file mode 100644 index 000000000..6bbc747b1 --- /dev/null +++ b/metadata-generator/TestFixtures/SwiftDemo/Sources/SwiftDemo/Extensions.swift @@ -0,0 +1,29 @@ +extension Demo { + public func greet(name: String, times: Int) -> String { + String(repeating: greet(name: name), count: times) + } + + public static var version: String { "1.0" } +} + +extension Point: CustomStringConvertible { + public var description: String { "(\(x), \(y))" } + public var length: Double { (x * x + y * y).squareRoot() } +} + +extension Flavor: CustomStringConvertible { + public var description: String { self == .vanilla ? "vanilla" : "chocolate" } +} + +extension String { + public var shouted: String { uppercased() + "!" } +} + +extension Array where Element == Point { + public func centroid() -> Point { + guard !isEmpty else { return Point(x: 0, y: 0) } + let sx = reduce(0) { $0 + $1.x } + let sy = reduce(0) { $0 + $1.y } + return Point(x: sx / Double(count), y: sy / Double(count)) + } +} diff --git a/metadata-generator/TestFixtures/SwiftDemo/Sources/SwiftDemo/Shapes.swift b/metadata-generator/TestFixtures/SwiftDemo/Sources/SwiftDemo/Shapes.swift new file mode 100644 index 000000000..0a6f1ec82 --- /dev/null +++ b/metadata-generator/TestFixtures/SwiftDemo/Sources/SwiftDemo/Shapes.swift @@ -0,0 +1,142 @@ +import Foundation + +public protocol Shape: Greeter { + var area: Double { get } + static var sides: Int { get } +} + +open class Polygon { + public let name: String + public private(set) var vertexCount: Int + public static let shared = Polygon(name: "shared", vertexCount: 0) + + public init(name: String, vertexCount: Int) { + self.name = name + self.vertexCount = vertexCount + } + + public convenience init?(name: String) { + guard !name.isEmpty else { return nil } + self.init(name: name, vertexCount: 0) + } + + open func scale(by factor: Double) {} + open func scale(by factor: Int) {} + public func scale(x: Double, y: Double) {} + + public class func make() -> Polygon { Polygon(name: "made", vertexCount: 3) } + public static func describe(_ polygon: Polygon?) -> String { polygon?.name ?? "none" } + + public subscript(index: Int) -> Point { Point(x: Double(index), y: 0) } + + internal func hiddenHelper() {} +} + +public final class Square: Polygon, Shape { + public var side: Double + + public init(side: Double) { + self.side = side + super.init(name: "square", vertexCount: 4) + } + + public var area: Double { side * side } + public static var sides: Int { 4 } + public func greet(name: String) -> String { "Square greets \(name)" } + + override public func scale(by factor: Double) { side *= factor } +} + +// A case named `none` must not be confused with Optional.none. +public enum Precipitation: String { + case rain, snow, none +} + +public enum ShapeError: Error { + case invalidSide(Double) + case tooManySides(count: Int, limit: Int) + case unknown +} + +public enum Measurement { + case length(Double) + case area(width: Double, height: Double) + case none + + public struct Unit { + public var symbol: String + public init(symbol: String) { self.symbol = symbol } + } + + public var isNone: Bool { + if case .none = self { return true } + return false + } +} + +public struct Ring { + public var inner: Point + public var outer: Point + + public init(inner: Point, outer: Point) { + self.inner = inner + self.outer = outer + } + + public mutating func expand(by delta: Double) { + outer.x += delta + outer.y += delta + } + + public static func + (lhs: Ring, rhs: Ring) -> Ring { + Ring(inner: lhs.inner, outer: rhs.outer) + } +} + +public actor Counter { + public private(set) var value: Int = 0 + public init() {} + public func increment() -> Int { + value += 1 + return value + } + public nonisolated func label() -> String { "counter" } +} + +@MainActor +public final class Canvas { + public init() {} + public func draw(_ shape: any Shape) {} +} + +public final class Loader { + public init() {} + + public func load(path: String) throws -> Data { Data() } + public func fetch(url: URL) async throws -> String { url.absoluteString } + public func wait(seconds: Double) async {} + + public func transform(_ shape: T) -> T { shape } + public func first(of items: [Element]) -> Element? { items.first } + + public func withCompletion(_ completion: @escaping (Result) -> Void) {} + public func each(_ body: (Int) -> Void) {} + + public func lookup(table: [String: Int], key: String) -> Int? { table[key] } + + public func update(_ point: inout Point) { point.x += 1 } + + @available(iOS 16.0, *) + public func modernOnly() {} + + @available(*, deprecated, message: "Use fetch(url:) instead") + public func legacyFetch() {} + + @available(iOS, introduced: 15.0, deprecated: 17.0, renamed: "fetch(url:)") + public func oldFetch() {} +} + +public func makeDefaultPoint() -> Point { Point(x: 0, y: 0) } +public let defaultFlavor: Flavor = .vanilla +public var globalCounter: Int = 0 +public typealias Coordinates = (latitude: Double, longitude: Double) diff --git a/metadata-generator/TestFixtures/SwiftDemo/Sources/SwiftDemo/Values.swift b/metadata-generator/TestFixtures/SwiftDemo/Sources/SwiftDemo/Values.swift new file mode 100644 index 000000000..4036b478c --- /dev/null +++ b/metadata-generator/TestFixtures/SwiftDemo/Sources/SwiftDemo/Values.swift @@ -0,0 +1,26 @@ +// Declarations the runtime tests use to exercise value marshaling, errors and +// object lifetime. + +public func checkedSide(_ side: Double) throws -> Double { + if side < 0 { throw ShapeError.invalidSide(side) } + return side +} + +public func echoInt8(_ value: Int8) -> Int8 { value } +public func echoUInt64(_ value: UInt64) -> UInt64 { value } +public func largestInt() -> Int { Int.max } +public func shout(_ name: String?) -> String? { name.map { $0.uppercased() } } + +public final class Tracker { + public private(set) static var liveCount = 0 + public let id: Int + + public init(id: Int) { + self.id = id + Tracker.liveCount += 1 + } + + deinit { Tracker.liveCount -= 1 } + + public func same() -> Tracker { self } +} diff --git a/metadata-generator/TestFixtures/SwiftDemo/generate-symbolgraphs.sh b/metadata-generator/TestFixtures/SwiftDemo/generate-symbolgraphs.sh new file mode 100755 index 000000000..d62314f8c --- /dev/null +++ b/metadata-generator/TestFixtures/SwiftDemo/generate-symbolgraphs.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# Regenerates the checked-in symbol graphs under symbolgraphs/. +# The parser tests snapshot these files, so regenerate only when the fixture +# sources change or when deliberately adopting a new toolchain's output. +set -euo pipefail + +FIXTURE_DIR="$(cd "$(dirname "$0")" && pwd)" +OUT_DIR="$FIXTURE_DIR/symbolgraphs" +WORK_DIR="$(mktemp -d)" +trap 'rm -rf "$WORK_DIR"' EXIT + +SDK_PATH="$(xcrun --sdk iphonesimulator --show-sdk-path)" + +xcrun swiftc \ + -emit-module \ + -emit-module-path "$WORK_DIR/SwiftDemo.swiftmodule" \ + -emit-symbol-graph \ + -emit-symbol-graph-dir "$WORK_DIR" \ + -symbol-graph-minimum-access-level public \ + -module-name SwiftDemo \ + -target arm64-apple-ios15.0-simulator \ + -sdk "$SDK_PATH" \ + "$FIXTURE_DIR"/Sources/SwiftDemo/*.swift + +rm -rf "$OUT_DIR" +mkdir -p "$OUT_DIR" +cp "$WORK_DIR"/*.symbols.json "$OUT_DIR/" + +# Absolute source paths differ per machine; keep the fixture reproducible. +sed -i '' "s#file://$FIXTURE_DIR/#file://#g" "$OUT_DIR"/*.symbols.json + +ls -1 "$OUT_DIR" diff --git a/metadata-generator/TestFixtures/SwiftDemo/symbolgraphs/SwiftDemo.symbols.json b/metadata-generator/TestFixtures/SwiftDemo/symbolgraphs/SwiftDemo.symbols.json new file mode 100644 index 000000000..141d999da --- /dev/null +++ b/metadata-generator/TestFixtures/SwiftDemo/symbolgraphs/SwiftDemo.symbols.json @@ -0,0 +1 @@ +{"metadata":{"formatVersion":{"major":0,"minor":6,"patch":0},"generator":"Apple Swift version 6.4 (swiftlang-6.4.0.34.1 clang-2100.3.34.1)"},"module":{"name":"SwiftDemo","platform":{"architecture":"arm64","environment":"simulator","vendor":"apple","operatingSystem":{"name":"ios","minimumVersion":{"major":15,"minor":0}}}},"symbols":[{"kind":{"identifier":"swift.protocol","displayName":"Protocol"},"identifier":{"precise":"s:9SwiftDemo7GreeterP","interfaceLanguage":"swift"},"pathComponents":["Greeter"],"names":{"title":"Greeter","navigator":[{"kind":"identifier","spelling":"Greeter"}],"subHeading":[{"kind":"keyword","spelling":"protocol"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Greeter"}]},"declarationFragments":[{"kind":"keyword","spelling":"protocol"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Greeter"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Demo.swift","position":{"line":0,"character":16}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo7GreeterP5greet4nameS2S_tF","interfaceLanguage":"swift"},"pathComponents":["Greeter","greet(name:)"],"names":{"title":"greet(name:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"greet"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"name"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},"functionSignature":{"parameters":[{"name":"name","declarationFragments":[{"kind":"identifier","spelling":"name"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]}],"returns":[{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"greet"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"name"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Demo.swift","position":{"line":1,"character":9}}},{"kind":{"identifier":"swift.class","displayName":"Class"},"identifier":{"precise":"s:9SwiftDemo0B0C","interfaceLanguage":"swift"},"pathComponents":["Demo"],"names":{"title":"Demo","navigator":[{"kind":"identifier","spelling":"Demo"}],"subHeading":[{"kind":"keyword","spelling":"class"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Demo"}]},"declarationFragments":[{"kind":"keyword","spelling":"class"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Demo"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Demo.swift","position":{"line":4,"character":13}}},{"kind":{"identifier":"swift.init","displayName":"Initializer"},"identifier":{"precise":"s:9SwiftDemo0B0CACycfc","interfaceLanguage":"swift"},"pathComponents":["Demo","init()"],"names":{"title":"init()","subHeading":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"()"}]},"functionSignature":{},"declarationFragments":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"()"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Demo.swift","position":{"line":5,"character":11}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo0B0C5greet4nameS2S_tF","interfaceLanguage":"swift"},"pathComponents":["Demo","greet(name:)"],"names":{"title":"greet(name:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"greet"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"name"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},"functionSignature":{"parameters":[{"name":"name","declarationFragments":[{"kind":"identifier","spelling":"name"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]}],"returns":[{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"greet"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"name"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Demo.swift","position":{"line":6,"character":16}}},{"kind":{"identifier":"swift.struct","displayName":"Structure"},"identifier":{"precise":"s:9SwiftDemo5PointV","interfaceLanguage":"swift"},"pathComponents":["Point"],"names":{"title":"Point","navigator":[{"kind":"identifier","spelling":"Point"}],"subHeading":[{"kind":"keyword","spelling":"struct"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Point"}]},"declarationFragments":[{"kind":"keyword","spelling":"struct"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Point"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Demo.swift","position":{"line":9,"character":14}}},{"kind":{"identifier":"swift.property","displayName":"Instance Property"},"identifier":{"precise":"s:9SwiftDemo5PointV1xSdvp","interfaceLanguage":"swift"},"pathComponents":["Point","x"],"names":{"title":"x","subHeading":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"x"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"}]},"declarationFragments":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"x"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Demo.swift","position":{"line":10,"character":15}}},{"kind":{"identifier":"swift.property","displayName":"Instance Property"},"identifier":{"precise":"s:9SwiftDemo5PointV1ySdvp","interfaceLanguage":"swift"},"pathComponents":["Point","y"],"names":{"title":"y","subHeading":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"y"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"}]},"declarationFragments":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"y"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Demo.swift","position":{"line":11,"character":15}}},{"kind":{"identifier":"swift.init","displayName":"Initializer"},"identifier":{"precise":"s:9SwiftDemo5PointV1x1yACSd_Sdtcfc","interfaceLanguage":"swift"},"pathComponents":["Point","init(x:y:)"],"names":{"title":"init(x:y:)","subHeading":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"x"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"y"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":")"}]},"functionSignature":{"parameters":[{"name":"x","declarationFragments":[{"kind":"identifier","spelling":"x"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"}]},{"name":"y","declarationFragments":[{"kind":"identifier","spelling":"y"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"}]}]},"declarationFragments":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"x"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"y"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":")"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Demo.swift","position":{"line":12,"character":11}}},{"kind":{"identifier":"swift.enum","displayName":"Enumeration"},"identifier":{"precise":"s:9SwiftDemo6FlavorO","interfaceLanguage":"swift"},"pathComponents":["Flavor"],"names":{"title":"Flavor","navigator":[{"kind":"identifier","spelling":"Flavor"}],"subHeading":[{"kind":"keyword","spelling":"enum"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Flavor"}]},"declarationFragments":[{"kind":"keyword","spelling":"enum"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Flavor"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Demo.swift","position":{"line":15,"character":12}}},{"kind":{"identifier":"swift.property","displayName":"Instance Property"},"identifier":{"precise":"s:SYsSHRzSH8RawValueSYRpzrlE04hashB0Sivp::SYNTHESIZED::s:9SwiftDemo6FlavorO","interfaceLanguage":"swift"},"pathComponents":["Flavor","hashValue"],"names":{"title":"hashValue","subHeading":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"hashValue"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"}]},"swiftExtension":{"extendedModule":"Swift","typeKind":"swift.protocol","constraints":[{"kind":"conformance","lhs":"Self","rhs":"Hashable","rhsPrecise":"s:SH"},{"kind":"conformance","lhs":"Self.RawValue","rhs":"Hashable","rhsPrecise":"s:SH"}]},"declarationFragments":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"hashValue"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":" { "},{"kind":"keyword","spelling":"get"},{"kind":"text","spelling":" }"}],"accessLevel":"public"},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:SYsSHRzSH8RawValueSYRpzrlE4hash4intoys6HasherVz_tF::SYNTHESIZED::s:9SwiftDemo6FlavorO","interfaceLanguage":"swift"},"pathComponents":["Flavor","hash(into:)"],"names":{"title":"hash(into:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"hash"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"into"},{"kind":"text","spelling":": "},{"kind":"keyword","spelling":"inout"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"Hasher","preciseIdentifier":"s:s6HasherV"},{"kind":"text","spelling":")"}]},"functionSignature":{"parameters":[{"name":"into","internalName":"hasher","declarationFragments":[{"kind":"identifier","spelling":"hasher"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Hasher","preciseIdentifier":"s:s6HasherV"}]}],"returns":[{"kind":"text","spelling":"()"}]},"swiftGenerics":{"constraints":[{"kind":"conformance","lhs":"Self","rhs":"Hashable","rhsPrecise":"s:SH"},{"kind":"conformance","lhs":"Self.RawValue","rhs":"Hashable","rhsPrecise":"s:SH"}]},"swiftExtension":{"extendedModule":"Swift","typeKind":"swift.protocol","constraints":[{"kind":"conformance","lhs":"Self","rhs":"Hashable","rhsPrecise":"s:SH"},{"kind":"conformance","lhs":"Self.RawValue","rhs":"Hashable","rhsPrecise":"s:SH"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"hash"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"into"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"hasher"},{"kind":"text","spelling":": "},{"kind":"keyword","spelling":"inout"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"Hasher","preciseIdentifier":"s:s6HasherV"},{"kind":"text","spelling":")"}],"accessLevel":"public"},{"kind":{"identifier":"swift.func.op","displayName":"Operator"},"identifier":{"precise":"s:SQsRi_zRi0_zrlE2neoiySbx_xtFZ::SYNTHESIZED::s:9SwiftDemo6FlavorO","interfaceLanguage":"swift"},"pathComponents":["Flavor","!=(_:_:)"],"names":{"title":"!=(_:_:)","subHeading":[{"kind":"keyword","spelling":"static"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"!="},{"kind":"text","spelling":" "},{"kind":"text","spelling":"("},{"kind":"keyword","spelling":"borrowing"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"Self"},{"kind":"text","spelling":", "},{"kind":"keyword","spelling":"borrowing"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"Self"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"Bool","preciseIdentifier":"s:Sb"}]},"docComment":{"module":"Swift","lines":[{"text":"Returns a Boolean value indicating whether two values are not equal."},{"text":""},{"text":"Inequality is the inverse of equality. For any values `a` and `b`, `a != b`"},{"text":"implies that `a == b` is `false`."},{"text":""},{"text":"This is the default implementation of the not-equal-to operator (`!=`)"},{"text":"for any type that conforms to `Equatable`."},{"text":""},{"text":"- Parameters:"},{"text":" - lhs: A value to compare."},{"text":" - rhs: Another value to compare."}]},"functionSignature":{"parameters":[{"name":"lhs","declarationFragments":[{"kind":"identifier","spelling":"lhs"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Self"}]},{"name":"rhs","declarationFragments":[{"kind":"identifier","spelling":"rhs"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Self"}]}],"returns":[{"kind":"typeIdentifier","spelling":"Bool","preciseIdentifier":"s:Sb"}]},"swiftExtension":{"extendedModule":"Swift","typeKind":"swift.protocol"},"declarationFragments":[{"kind":"keyword","spelling":"static"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"!="},{"kind":"text","spelling":" "},{"kind":"text","spelling":"("},{"kind":"internalParam","spelling":"lhs"},{"kind":"text","spelling":": "},{"kind":"keyword","spelling":"borrowing"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"Self"},{"kind":"text","spelling":", "},{"kind":"internalParam","spelling":"rhs"},{"kind":"text","spelling":": "},{"kind":"keyword","spelling":"borrowing"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"Self"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"Bool","preciseIdentifier":"s:Sb"}],"accessLevel":"public"},{"kind":{"identifier":"swift.enum.case","displayName":"Case"},"identifier":{"precise":"s:9SwiftDemo6FlavorO7vanillayA2CmF","interfaceLanguage":"swift"},"pathComponents":["Flavor","vanilla"],"names":{"title":"Flavor.vanilla","subHeading":[{"kind":"keyword","spelling":"case"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"vanilla"}]},"declarationFragments":[{"kind":"keyword","spelling":"case"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"vanilla"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Demo.swift","position":{"line":15,"character":31}}},{"kind":{"identifier":"swift.enum.case","displayName":"Case"},"identifier":{"precise":"s:9SwiftDemo6FlavorO9chocolateyA2CmF","interfaceLanguage":"swift"},"pathComponents":["Flavor","chocolate"],"names":{"title":"Flavor.chocolate","subHeading":[{"kind":"keyword","spelling":"case"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"chocolate"}]},"declarationFragments":[{"kind":"keyword","spelling":"case"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"chocolate"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Demo.swift","position":{"line":15,"character":44}}},{"kind":{"identifier":"swift.init","displayName":"Initializer"},"identifier":{"precise":"s:9SwiftDemo6FlavorO8rawValueACSgSi_tcfc","interfaceLanguage":"swift"},"pathComponents":["Flavor","init(rawValue:)"],"names":{"title":"init(rawValue:)","subHeading":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"?("},{"kind":"externalParam","spelling":"rawValue"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":")"}]},"functionSignature":{"parameters":[{"name":"rawValue","declarationFragments":[{"kind":"identifier","spelling":"rawValue"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"}]}]},"declarationFragments":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"?("},{"kind":"externalParam","spelling":"rawValue"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":")"}],"accessLevel":"public"},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo0B0C5greet4name5timesS2S_SitF","interfaceLanguage":"swift"},"pathComponents":["Demo","greet(name:times:)"],"names":{"title":"greet(name:times:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"greet"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"name"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"times"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},"functionSignature":{"parameters":[{"name":"name","declarationFragments":[{"kind":"identifier","spelling":"name"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},{"name":"times","declarationFragments":[{"kind":"identifier","spelling":"times"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"}]}],"returns":[{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},"swiftExtension":{"extendedModule":"SwiftDemo","typeKind":"swift.class"},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"greet"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"name"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"times"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Extensions.swift","position":{"line":1,"character":16}}},{"kind":{"identifier":"swift.type.property","displayName":"Type Property"},"identifier":{"precise":"s:9SwiftDemo0B0C7versionSSvpZ","interfaceLanguage":"swift"},"pathComponents":["Demo","version"],"names":{"title":"version","subHeading":[{"kind":"keyword","spelling":"static"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"version"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},"swiftExtension":{"extendedModule":"SwiftDemo","typeKind":"swift.class"},"declarationFragments":[{"kind":"keyword","spelling":"static"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"version"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":" { "},{"kind":"keyword","spelling":"get"},{"kind":"text","spelling":" }"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Extensions.swift","position":{"line":5,"character":22}}},{"kind":{"identifier":"swift.property","displayName":"Instance Property"},"identifier":{"precise":"s:9SwiftDemo5PointV11descriptionSSvp","interfaceLanguage":"swift"},"pathComponents":["Point","description"],"names":{"title":"description","subHeading":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"description"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},"swiftExtension":{"extendedModule":"SwiftDemo","typeKind":"swift.struct"},"declarationFragments":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"description"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":" { "},{"kind":"keyword","spelling":"get"},{"kind":"text","spelling":" }"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Extensions.swift","position":{"line":9,"character":15}}},{"kind":{"identifier":"swift.property","displayName":"Instance Property"},"identifier":{"precise":"s:9SwiftDemo5PointV6lengthSdvp","interfaceLanguage":"swift"},"pathComponents":["Point","length"],"names":{"title":"length","subHeading":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"length"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"}]},"swiftExtension":{"extendedModule":"SwiftDemo","typeKind":"swift.struct"},"declarationFragments":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"length"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":" { "},{"kind":"keyword","spelling":"get"},{"kind":"text","spelling":" }"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Extensions.swift","position":{"line":10,"character":15}}},{"kind":{"identifier":"swift.property","displayName":"Instance Property"},"identifier":{"precise":"s:9SwiftDemo6FlavorO11descriptionSSvp","interfaceLanguage":"swift"},"pathComponents":["Flavor","description"],"names":{"title":"description","subHeading":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"description"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},"swiftExtension":{"extendedModule":"SwiftDemo","typeKind":"swift.enum"},"declarationFragments":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"description"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":" { "},{"kind":"keyword","spelling":"get"},{"kind":"text","spelling":" }"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Extensions.swift","position":{"line":14,"character":15}}},{"kind":{"identifier":"swift.protocol","displayName":"Protocol"},"identifier":{"precise":"s:9SwiftDemo5ShapeP","interfaceLanguage":"swift"},"pathComponents":["Shape"],"names":{"title":"Shape","navigator":[{"kind":"identifier","spelling":"Shape"}],"subHeading":[{"kind":"keyword","spelling":"protocol"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Shape"}]},"declarationFragments":[{"kind":"keyword","spelling":"protocol"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Shape"},{"kind":"text","spelling":" : "},{"kind":"typeIdentifier","spelling":"Greeter","preciseIdentifier":"s:9SwiftDemo7GreeterP"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":2,"character":16}}},{"kind":{"identifier":"swift.property","displayName":"Instance Property"},"identifier":{"precise":"s:9SwiftDemo5ShapeP4areaSdvp","interfaceLanguage":"swift"},"pathComponents":["Shape","area"],"names":{"title":"area","subHeading":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"area"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"}]},"declarationFragments":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"area"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":" { "},{"kind":"keyword","spelling":"get"},{"kind":"text","spelling":" }"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":3,"character":8}}},{"kind":{"identifier":"swift.type.property","displayName":"Type Property"},"identifier":{"precise":"s:9SwiftDemo5ShapeP5sidesSivpZ","interfaceLanguage":"swift"},"pathComponents":["Shape","sides"],"names":{"title":"sides","subHeading":[{"kind":"keyword","spelling":"static"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"sides"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"}]},"declarationFragments":[{"kind":"keyword","spelling":"static"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"sides"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":" { "},{"kind":"keyword","spelling":"get"},{"kind":"text","spelling":" }"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":4,"character":15}}},{"kind":{"identifier":"swift.class","displayName":"Class"},"identifier":{"precise":"s:9SwiftDemo7PolygonC","interfaceLanguage":"swift"},"pathComponents":["Polygon"],"names":{"title":"Polygon","navigator":[{"kind":"identifier","spelling":"Polygon"}],"subHeading":[{"kind":"keyword","spelling":"class"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Polygon"}]},"declarationFragments":[{"kind":"keyword","spelling":"class"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Polygon"}],"accessLevel":"open","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":7,"character":11}}},{"kind":{"identifier":"swift.property","displayName":"Instance Property"},"identifier":{"precise":"s:9SwiftDemo7PolygonC4nameSSvp","interfaceLanguage":"swift"},"pathComponents":["Polygon","name"],"names":{"title":"name","subHeading":[{"kind":"keyword","spelling":"let"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"name"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},"declarationFragments":[{"kind":"keyword","spelling":"let"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"name"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":8,"character":15}}},{"kind":{"identifier":"swift.property","displayName":"Instance Property"},"identifier":{"precise":"s:9SwiftDemo7PolygonC11vertexCountSivp","interfaceLanguage":"swift"},"pathComponents":["Polygon","vertexCount"],"names":{"title":"vertexCount","subHeading":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"vertexCount"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"}]},"declarationFragments":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"vertexCount"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":" { get }"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":9,"character":28}}},{"kind":{"identifier":"swift.type.property","displayName":"Type Property"},"identifier":{"precise":"s:9SwiftDemo7PolygonC6sharedACvpZ","interfaceLanguage":"swift"},"pathComponents":["Polygon","shared"],"names":{"title":"shared","subHeading":[{"kind":"keyword","spelling":"static"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"let"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"shared"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Polygon","preciseIdentifier":"s:9SwiftDemo7PolygonC"}]},"declarationFragments":[{"kind":"keyword","spelling":"static"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"let"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"shared"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Polygon","preciseIdentifier":"s:9SwiftDemo7PolygonC"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":10,"character":22}}},{"kind":{"identifier":"swift.init","displayName":"Initializer"},"identifier":{"precise":"s:9SwiftDemo7PolygonC4name11vertexCountACSS_Sitcfc","interfaceLanguage":"swift"},"pathComponents":["Polygon","init(name:vertexCount:)"],"names":{"title":"init(name:vertexCount:)","subHeading":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"name"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"vertexCount"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":")"}]},"functionSignature":{"parameters":[{"name":"name","declarationFragments":[{"kind":"identifier","spelling":"name"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},{"name":"vertexCount","declarationFragments":[{"kind":"identifier","spelling":"vertexCount"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"}]}]},"declarationFragments":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"name"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"vertexCount"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":")"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":12,"character":11}}},{"kind":{"identifier":"swift.init","displayName":"Initializer"},"identifier":{"precise":"s:9SwiftDemo7PolygonC4nameACSgSS_tcfc","interfaceLanguage":"swift"},"pathComponents":["Polygon","init(name:)"],"names":{"title":"init(name:)","subHeading":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"?("},{"kind":"externalParam","spelling":"name"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":")"}]},"functionSignature":{"parameters":[{"name":"name","declarationFragments":[{"kind":"identifier","spelling":"name"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]}]},"declarationFragments":[{"kind":"keyword","spelling":"convenience"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"?("},{"kind":"externalParam","spelling":"name"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":")"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":17,"character":23}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo7PolygonC5scale2byySd_tF","interfaceLanguage":"swift"},"pathComponents":["Polygon","scale(by:)"],"names":{"title":"scale(by:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"scale"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"by"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":")"}]},"functionSignature":{"parameters":[{"name":"by","internalName":"factor","declarationFragments":[{"kind":"identifier","spelling":"factor"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"}]}],"returns":[{"kind":"text","spelling":"()"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"scale"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"by"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"factor"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":")"}],"accessLevel":"open","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":22,"character":14}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo7PolygonC5scale2byySi_tF","interfaceLanguage":"swift"},"pathComponents":["Polygon","scale(by:)"],"names":{"title":"scale(by:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"scale"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"by"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":")"}]},"functionSignature":{"parameters":[{"name":"by","internalName":"factor","declarationFragments":[{"kind":"identifier","spelling":"factor"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"}]}],"returns":[{"kind":"text","spelling":"()"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"scale"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"by"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"factor"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":")"}],"accessLevel":"open","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":23,"character":14}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo7PolygonC5scale1x1yySd_SdtF","interfaceLanguage":"swift"},"pathComponents":["Polygon","scale(x:y:)"],"names":{"title":"scale(x:y:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"scale"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"x"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"y"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":")"}]},"functionSignature":{"parameters":[{"name":"x","declarationFragments":[{"kind":"identifier","spelling":"x"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"}]},{"name":"y","declarationFragments":[{"kind":"identifier","spelling":"y"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"}]}],"returns":[{"kind":"text","spelling":"()"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"scale"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"x"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"y"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":")"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":24,"character":16}}},{"kind":{"identifier":"swift.type.method","displayName":"Type Method"},"identifier":{"precise":"s:9SwiftDemo7PolygonC4makeACyFZ","interfaceLanguage":"swift"},"pathComponents":["Polygon","make()"],"names":{"title":"make()","subHeading":[{"kind":"keyword","spelling":"class"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"make"},{"kind":"text","spelling":"() -> "},{"kind":"typeIdentifier","spelling":"Polygon","preciseIdentifier":"s:9SwiftDemo7PolygonC"}]},"functionSignature":{"returns":[{"kind":"typeIdentifier","spelling":"Polygon","preciseIdentifier":"s:9SwiftDemo7PolygonC"}]},"declarationFragments":[{"kind":"keyword","spelling":"class"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"make"},{"kind":"text","spelling":"() -> "},{"kind":"typeIdentifier","spelling":"Polygon","preciseIdentifier":"s:9SwiftDemo7PolygonC"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":26,"character":22}}},{"kind":{"identifier":"swift.type.method","displayName":"Type Method"},"identifier":{"precise":"s:9SwiftDemo7PolygonC8describeySSACSgFZ","interfaceLanguage":"swift"},"pathComponents":["Polygon","describe(_:)"],"names":{"title":"describe(_:)","subHeading":[{"kind":"keyword","spelling":"static"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"describe"},{"kind":"text","spelling":"("},{"kind":"typeIdentifier","spelling":"Polygon","preciseIdentifier":"s:9SwiftDemo7PolygonC"},{"kind":"text","spelling":"?) -> "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},"functionSignature":{"parameters":[{"name":"polygon","declarationFragments":[{"kind":"identifier","spelling":"polygon"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Polygon","preciseIdentifier":"s:9SwiftDemo7PolygonC"},{"kind":"text","spelling":"?"}]}],"returns":[{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},"declarationFragments":[{"kind":"keyword","spelling":"static"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"describe"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"_"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"polygon"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Polygon","preciseIdentifier":"s:9SwiftDemo7PolygonC"},{"kind":"text","spelling":"?) -> "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":27,"character":23}}},{"kind":{"identifier":"swift.subscript","displayName":"Instance Subscript"},"identifier":{"precise":"s:9SwiftDemo7PolygonCyAA5PointVSicip","interfaceLanguage":"swift"},"pathComponents":["Polygon","subscript(_:)"],"names":{"title":"subscript(_:)","subHeading":[{"kind":"keyword","spelling":"subscript"},{"kind":"text","spelling":"("},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"Point","preciseIdentifier":"s:9SwiftDemo5PointV"}]},"functionSignature":{"parameters":[{"name":"index","declarationFragments":[{"kind":"identifier","spelling":"index"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"}]}],"returns":[{"kind":"typeIdentifier","spelling":"Point","preciseIdentifier":"s:9SwiftDemo5PointV"}]},"declarationFragments":[{"kind":"keyword","spelling":"subscript"},{"kind":"text","spelling":"("},{"kind":"internalParam","spelling":"index"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"Point","preciseIdentifier":"s:9SwiftDemo5PointV"},{"kind":"text","spelling":" { "},{"kind":"keyword","spelling":"get"},{"kind":"text","spelling":" }"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":29,"character":11}}},{"kind":{"identifier":"swift.class","displayName":"Class"},"identifier":{"precise":"s:9SwiftDemo6SquareC","interfaceLanguage":"swift"},"pathComponents":["Square"],"names":{"title":"Square","navigator":[{"kind":"identifier","spelling":"Square"}],"subHeading":[{"kind":"keyword","spelling":"class"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Square"}]},"declarationFragments":[{"kind":"keyword","spelling":"final"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"class"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Square"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":34,"character":19}}},{"kind":{"identifier":"swift.property","displayName":"Instance Property"},"identifier":{"precise":"s:9SwiftDemo6SquareC4sideSdvp","interfaceLanguage":"swift"},"pathComponents":["Square","side"],"names":{"title":"side","subHeading":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"side"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"}]},"declarationFragments":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"side"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":35,"character":15}}},{"kind":{"identifier":"swift.init","displayName":"Initializer"},"identifier":{"precise":"s:9SwiftDemo6SquareC4sideACSd_tcfc","interfaceLanguage":"swift"},"pathComponents":["Square","init(side:)"],"names":{"title":"init(side:)","subHeading":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"side"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":")"}]},"functionSignature":{"parameters":[{"name":"side","declarationFragments":[{"kind":"identifier","spelling":"side"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"}]}]},"declarationFragments":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"side"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":")"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":37,"character":11}}},{"kind":{"identifier":"swift.property","displayName":"Instance Property"},"identifier":{"precise":"s:9SwiftDemo6SquareC4areaSdvp","interfaceLanguage":"swift"},"pathComponents":["Square","area"],"names":{"title":"area","subHeading":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"area"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"}]},"declarationFragments":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"area"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":" { "},{"kind":"keyword","spelling":"get"},{"kind":"text","spelling":" }"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":42,"character":15}}},{"kind":{"identifier":"swift.type.property","displayName":"Type Property"},"identifier":{"precise":"s:9SwiftDemo6SquareC5sidesSivpZ","interfaceLanguage":"swift"},"pathComponents":["Square","sides"],"names":{"title":"sides","subHeading":[{"kind":"keyword","spelling":"static"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"sides"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"}]},"declarationFragments":[{"kind":"keyword","spelling":"static"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"sides"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":" { "},{"kind":"keyword","spelling":"get"},{"kind":"text","spelling":" }"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":43,"character":22}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo6SquareC5greet4nameS2S_tF","interfaceLanguage":"swift"},"pathComponents":["Square","greet(name:)"],"names":{"title":"greet(name:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"greet"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"name"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},"functionSignature":{"parameters":[{"name":"name","declarationFragments":[{"kind":"identifier","spelling":"name"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]}],"returns":[{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"greet"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"name"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":44,"character":16}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo6SquareC5scale2byySd_tF","interfaceLanguage":"swift"},"pathComponents":["Square","scale(by:)"],"names":{"title":"scale(by:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"scale"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"by"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":")"}]},"functionSignature":{"parameters":[{"name":"by","internalName":"factor","declarationFragments":[{"kind":"identifier","spelling":"factor"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"}]}],"returns":[{"kind":"text","spelling":"()"}]},"declarationFragments":[{"kind":"keyword","spelling":"override"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"scale"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"by"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"factor"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":")"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":46,"character":25}}},{"kind":{"identifier":"swift.enum","displayName":"Enumeration"},"identifier":{"precise":"s:9SwiftDemo13PrecipitationO","interfaceLanguage":"swift"},"pathComponents":["Precipitation"],"names":{"title":"Precipitation","navigator":[{"kind":"identifier","spelling":"Precipitation"}],"subHeading":[{"kind":"keyword","spelling":"enum"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Precipitation"}]},"declarationFragments":[{"kind":"keyword","spelling":"enum"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Precipitation"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":50,"character":12}}},{"kind":{"identifier":"swift.property","displayName":"Instance Property"},"identifier":{"precise":"s:SYsSHRzSH8RawValueSYRpzrlE04hashB0Sivp::SYNTHESIZED::s:9SwiftDemo13PrecipitationO","interfaceLanguage":"swift"},"pathComponents":["Precipitation","hashValue"],"names":{"title":"hashValue","subHeading":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"hashValue"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"}]},"swiftExtension":{"extendedModule":"Swift","typeKind":"swift.protocol","constraints":[{"kind":"conformance","lhs":"Self","rhs":"Hashable","rhsPrecise":"s:SH"},{"kind":"conformance","lhs":"Self.RawValue","rhs":"Hashable","rhsPrecise":"s:SH"}]},"declarationFragments":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"hashValue"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":" { "},{"kind":"keyword","spelling":"get"},{"kind":"text","spelling":" }"}],"accessLevel":"public"},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:SYsSHRzSH8RawValueSYRpzrlE4hash4intoys6HasherVz_tF::SYNTHESIZED::s:9SwiftDemo13PrecipitationO","interfaceLanguage":"swift"},"pathComponents":["Precipitation","hash(into:)"],"names":{"title":"hash(into:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"hash"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"into"},{"kind":"text","spelling":": "},{"kind":"keyword","spelling":"inout"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"Hasher","preciseIdentifier":"s:s6HasherV"},{"kind":"text","spelling":")"}]},"functionSignature":{"parameters":[{"name":"into","internalName":"hasher","declarationFragments":[{"kind":"identifier","spelling":"hasher"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Hasher","preciseIdentifier":"s:s6HasherV"}]}],"returns":[{"kind":"text","spelling":"()"}]},"swiftGenerics":{"constraints":[{"kind":"conformance","lhs":"Self","rhs":"Hashable","rhsPrecise":"s:SH"},{"kind":"conformance","lhs":"Self.RawValue","rhs":"Hashable","rhsPrecise":"s:SH"}]},"swiftExtension":{"extendedModule":"Swift","typeKind":"swift.protocol","constraints":[{"kind":"conformance","lhs":"Self","rhs":"Hashable","rhsPrecise":"s:SH"},{"kind":"conformance","lhs":"Self.RawValue","rhs":"Hashable","rhsPrecise":"s:SH"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"hash"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"into"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"hasher"},{"kind":"text","spelling":": "},{"kind":"keyword","spelling":"inout"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"Hasher","preciseIdentifier":"s:s6HasherV"},{"kind":"text","spelling":")"}],"accessLevel":"public"},{"kind":{"identifier":"swift.func.op","displayName":"Operator"},"identifier":{"precise":"s:SQsRi_zRi0_zrlE2neoiySbx_xtFZ::SYNTHESIZED::s:9SwiftDemo13PrecipitationO","interfaceLanguage":"swift"},"pathComponents":["Precipitation","!=(_:_:)"],"names":{"title":"!=(_:_:)","subHeading":[{"kind":"keyword","spelling":"static"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"!="},{"kind":"text","spelling":" "},{"kind":"text","spelling":"("},{"kind":"keyword","spelling":"borrowing"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"Self"},{"kind":"text","spelling":", "},{"kind":"keyword","spelling":"borrowing"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"Self"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"Bool","preciseIdentifier":"s:Sb"}]},"docComment":{"module":"Swift","lines":[{"text":"Returns a Boolean value indicating whether two values are not equal."},{"text":""},{"text":"Inequality is the inverse of equality. For any values `a` and `b`, `a != b`"},{"text":"implies that `a == b` is `false`."},{"text":""},{"text":"This is the default implementation of the not-equal-to operator (`!=`)"},{"text":"for any type that conforms to `Equatable`."},{"text":""},{"text":"- Parameters:"},{"text":" - lhs: A value to compare."},{"text":" - rhs: Another value to compare."}]},"functionSignature":{"parameters":[{"name":"lhs","declarationFragments":[{"kind":"identifier","spelling":"lhs"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Self"}]},{"name":"rhs","declarationFragments":[{"kind":"identifier","spelling":"rhs"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Self"}]}],"returns":[{"kind":"typeIdentifier","spelling":"Bool","preciseIdentifier":"s:Sb"}]},"swiftExtension":{"extendedModule":"Swift","typeKind":"swift.protocol"},"declarationFragments":[{"kind":"keyword","spelling":"static"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"!="},{"kind":"text","spelling":" "},{"kind":"text","spelling":"("},{"kind":"internalParam","spelling":"lhs"},{"kind":"text","spelling":": "},{"kind":"keyword","spelling":"borrowing"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"Self"},{"kind":"text","spelling":", "},{"kind":"internalParam","spelling":"rhs"},{"kind":"text","spelling":": "},{"kind":"keyword","spelling":"borrowing"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"Self"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"Bool","preciseIdentifier":"s:Sb"}],"accessLevel":"public"},{"kind":{"identifier":"swift.enum.case","displayName":"Case"},"identifier":{"precise":"s:9SwiftDemo13PrecipitationO4rainyA2CmF","interfaceLanguage":"swift"},"pathComponents":["Precipitation","rain"],"names":{"title":"Precipitation.rain","subHeading":[{"kind":"keyword","spelling":"case"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"rain"}]},"declarationFragments":[{"kind":"keyword","spelling":"case"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"rain"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":51,"character":9}}},{"kind":{"identifier":"swift.enum.case","displayName":"Case"},"identifier":{"precise":"s:9SwiftDemo13PrecipitationO4snowyA2CmF","interfaceLanguage":"swift"},"pathComponents":["Precipitation","snow"],"names":{"title":"Precipitation.snow","subHeading":[{"kind":"keyword","spelling":"case"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"snow"}]},"declarationFragments":[{"kind":"keyword","spelling":"case"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"snow"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":51,"character":15}}},{"kind":{"identifier":"swift.enum.case","displayName":"Case"},"identifier":{"precise":"s:9SwiftDemo13PrecipitationO4noneyA2CmF","interfaceLanguage":"swift"},"pathComponents":["Precipitation","none"],"names":{"title":"Precipitation.none","subHeading":[{"kind":"keyword","spelling":"case"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"none"}]},"declarationFragments":[{"kind":"keyword","spelling":"case"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"none"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":51,"character":21}}},{"kind":{"identifier":"swift.init","displayName":"Initializer"},"identifier":{"precise":"s:9SwiftDemo13PrecipitationO8rawValueACSgSS_tcfc","interfaceLanguage":"swift"},"pathComponents":["Precipitation","init(rawValue:)"],"names":{"title":"init(rawValue:)","subHeading":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"?("},{"kind":"externalParam","spelling":"rawValue"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":")"}]},"functionSignature":{"parameters":[{"name":"rawValue","declarationFragments":[{"kind":"identifier","spelling":"rawValue"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]}]},"declarationFragments":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"?("},{"kind":"externalParam","spelling":"rawValue"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":")"}],"accessLevel":"public"},{"kind":{"identifier":"swift.enum","displayName":"Enumeration"},"identifier":{"precise":"s:9SwiftDemo10ShapeErrorO","interfaceLanguage":"swift"},"pathComponents":["ShapeError"],"names":{"title":"ShapeError","navigator":[{"kind":"identifier","spelling":"ShapeError"}],"subHeading":[{"kind":"keyword","spelling":"enum"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"ShapeError"}]},"declarationFragments":[{"kind":"keyword","spelling":"enum"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"ShapeError"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":54,"character":12}}},{"kind":{"identifier":"swift.property","displayName":"Instance Property"},"identifier":{"precise":"s:s5ErrorP10FoundationE20localizedDescriptionSSvp::SYNTHESIZED::s:9SwiftDemo10ShapeErrorO","interfaceLanguage":"swift"},"pathComponents":["ShapeError","localizedDescription"],"names":{"title":"localizedDescription","subHeading":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"localizedDescription"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},"docComment":{"module":"Foundation","lines":[{"text":"Retrieve the localized description for this error."}]},"swiftExtension":{"extendedModule":"Swift","typeKind":"swift.protocol"},"declarationFragments":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"localizedDescription"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":" { "},{"kind":"keyword","spelling":"get"},{"kind":"text","spelling":" }"}],"accessLevel":"public","availability":[{"domain":"iOS","introduced":{"major":8,"minor":0}},{"domain":"macOS","introduced":{"major":10,"minor":10}},{"domain":"tvOS","introduced":{"major":9,"minor":0}},{"domain":"watchOS","introduced":{"major":2,"minor":0}}]},{"kind":{"identifier":"swift.enum.case","displayName":"Case"},"identifier":{"precise":"s:9SwiftDemo10ShapeErrorO11invalidSideyACSdcACmF","interfaceLanguage":"swift"},"pathComponents":["ShapeError","invalidSide(_:)"],"names":{"title":"ShapeError.invalidSide(_:)","subHeading":[{"kind":"keyword","spelling":"case"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"invalidSide"},{"kind":"text","spelling":"("},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":")"}]},"declarationFragments":[{"kind":"keyword","spelling":"case"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"invalidSide"},{"kind":"text","spelling":"("},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":")"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":55,"character":9}}},{"kind":{"identifier":"swift.enum.case","displayName":"Case"},"identifier":{"precise":"s:9SwiftDemo10ShapeErrorO12tooManySidesyACSi_SitcACmF","interfaceLanguage":"swift"},"pathComponents":["ShapeError","tooManySides(count:limit:)"],"names":{"title":"ShapeError.tooManySides(count:limit:)","subHeading":[{"kind":"keyword","spelling":"case"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"tooManySides"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"count"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"limit"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":")"}]},"declarationFragments":[{"kind":"keyword","spelling":"case"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"tooManySides"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"count"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"limit"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":")"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":56,"character":9}}},{"kind":{"identifier":"swift.enum.case","displayName":"Case"},"identifier":{"precise":"s:9SwiftDemo10ShapeErrorO7unknownyA2CmF","interfaceLanguage":"swift"},"pathComponents":["ShapeError","unknown"],"names":{"title":"ShapeError.unknown","subHeading":[{"kind":"keyword","spelling":"case"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"unknown"}]},"declarationFragments":[{"kind":"keyword","spelling":"case"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"unknown"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":57,"character":9}}},{"kind":{"identifier":"swift.enum","displayName":"Enumeration"},"identifier":{"precise":"s:9SwiftDemo11MeasurementO","interfaceLanguage":"swift"},"pathComponents":["Measurement"],"names":{"title":"Measurement","navigator":[{"kind":"identifier","spelling":"Measurement"}],"subHeading":[{"kind":"keyword","spelling":"enum"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Measurement"}]},"declarationFragments":[{"kind":"keyword","spelling":"enum"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Measurement"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":60,"character":12}}},{"kind":{"identifier":"swift.enum.case","displayName":"Case"},"identifier":{"precise":"s:9SwiftDemo11MeasurementO6lengthyACSdcACmF","interfaceLanguage":"swift"},"pathComponents":["Measurement","length(_:)"],"names":{"title":"Measurement.length(_:)","subHeading":[{"kind":"keyword","spelling":"case"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"length"},{"kind":"text","spelling":"("},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":")"}]},"declarationFragments":[{"kind":"keyword","spelling":"case"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"length"},{"kind":"text","spelling":"("},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":")"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":61,"character":9}}},{"kind":{"identifier":"swift.enum.case","displayName":"Case"},"identifier":{"precise":"s:9SwiftDemo11MeasurementO4areayACSd_SdtcACmF","interfaceLanguage":"swift"},"pathComponents":["Measurement","area(width:height:)"],"names":{"title":"Measurement.area(width:height:)","subHeading":[{"kind":"keyword","spelling":"case"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"area"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"width"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"height"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":")"}]},"declarationFragments":[{"kind":"keyword","spelling":"case"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"area"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"width"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"height"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":")"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":62,"character":9}}},{"kind":{"identifier":"swift.enum.case","displayName":"Case"},"identifier":{"precise":"s:9SwiftDemo11MeasurementO4noneyA2CmF","interfaceLanguage":"swift"},"pathComponents":["Measurement","none"],"names":{"title":"Measurement.none","subHeading":[{"kind":"keyword","spelling":"case"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"none"}]},"declarationFragments":[{"kind":"keyword","spelling":"case"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"none"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":63,"character":9}}},{"kind":{"identifier":"swift.struct","displayName":"Structure"},"identifier":{"precise":"s:9SwiftDemo11MeasurementO4UnitV","interfaceLanguage":"swift"},"pathComponents":["Measurement","Unit"],"names":{"title":"Measurement.Unit","navigator":[{"kind":"identifier","spelling":"Unit"}],"subHeading":[{"kind":"keyword","spelling":"struct"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Unit"}]},"declarationFragments":[{"kind":"keyword","spelling":"struct"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Unit"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":65,"character":18}}},{"kind":{"identifier":"swift.property","displayName":"Instance Property"},"identifier":{"precise":"s:9SwiftDemo11MeasurementO4UnitV6symbolSSvp","interfaceLanguage":"swift"},"pathComponents":["Measurement","Unit","symbol"],"names":{"title":"symbol","subHeading":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"symbol"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},"declarationFragments":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"symbol"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":66,"character":19}}},{"kind":{"identifier":"swift.init","displayName":"Initializer"},"identifier":{"precise":"s:9SwiftDemo11MeasurementO4UnitV6symbolAESS_tcfc","interfaceLanguage":"swift"},"pathComponents":["Measurement","Unit","init(symbol:)"],"names":{"title":"init(symbol:)","subHeading":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"symbol"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":")"}]},"functionSignature":{"parameters":[{"name":"symbol","declarationFragments":[{"kind":"identifier","spelling":"symbol"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]}]},"declarationFragments":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"symbol"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":")"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":67,"character":15}}},{"kind":{"identifier":"swift.property","displayName":"Instance Property"},"identifier":{"precise":"s:9SwiftDemo11MeasurementO6isNoneSbvp","interfaceLanguage":"swift"},"pathComponents":["Measurement","isNone"],"names":{"title":"isNone","subHeading":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"isNone"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Bool","preciseIdentifier":"s:Sb"}]},"declarationFragments":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"isNone"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Bool","preciseIdentifier":"s:Sb"},{"kind":"text","spelling":" { "},{"kind":"keyword","spelling":"get"},{"kind":"text","spelling":" }"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":70,"character":15}}},{"kind":{"identifier":"swift.struct","displayName":"Structure"},"identifier":{"precise":"s:9SwiftDemo4RingV","interfaceLanguage":"swift"},"pathComponents":["Ring"],"names":{"title":"Ring","navigator":[{"kind":"identifier","spelling":"Ring"}],"subHeading":[{"kind":"keyword","spelling":"struct"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Ring"}]},"declarationFragments":[{"kind":"keyword","spelling":"struct"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Ring"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":76,"character":14}}},{"kind":{"identifier":"swift.property","displayName":"Instance Property"},"identifier":{"precise":"s:9SwiftDemo4RingV5innerAA5PointVvp","interfaceLanguage":"swift"},"pathComponents":["Ring","inner"],"names":{"title":"inner","subHeading":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"inner"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Point","preciseIdentifier":"s:9SwiftDemo5PointV"}]},"declarationFragments":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"inner"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Point","preciseIdentifier":"s:9SwiftDemo5PointV"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":77,"character":15}}},{"kind":{"identifier":"swift.property","displayName":"Instance Property"},"identifier":{"precise":"s:9SwiftDemo4RingV5outerAA5PointVvp","interfaceLanguage":"swift"},"pathComponents":["Ring","outer"],"names":{"title":"outer","subHeading":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"outer"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Point","preciseIdentifier":"s:9SwiftDemo5PointV"}]},"declarationFragments":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"outer"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Point","preciseIdentifier":"s:9SwiftDemo5PointV"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":78,"character":15}}},{"kind":{"identifier":"swift.init","displayName":"Initializer"},"identifier":{"precise":"s:9SwiftDemo4RingV5inner5outerAcA5PointV_AGtcfc","interfaceLanguage":"swift"},"pathComponents":["Ring","init(inner:outer:)"],"names":{"title":"init(inner:outer:)","subHeading":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"inner"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Point","preciseIdentifier":"s:9SwiftDemo5PointV"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"outer"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Point","preciseIdentifier":"s:9SwiftDemo5PointV"},{"kind":"text","spelling":")"}]},"functionSignature":{"parameters":[{"name":"inner","declarationFragments":[{"kind":"identifier","spelling":"inner"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Point","preciseIdentifier":"s:9SwiftDemo5PointV"}]},{"name":"outer","declarationFragments":[{"kind":"identifier","spelling":"outer"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Point","preciseIdentifier":"s:9SwiftDemo5PointV"}]}]},"declarationFragments":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"inner"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Point","preciseIdentifier":"s:9SwiftDemo5PointV"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"outer"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Point","preciseIdentifier":"s:9SwiftDemo5PointV"},{"kind":"text","spelling":")"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":80,"character":11}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo4RingV6expand2byySd_tF","interfaceLanguage":"swift"},"pathComponents":["Ring","expand(by:)"],"names":{"title":"expand(by:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"expand"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"by"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":")"}]},"functionSignature":{"parameters":[{"name":"by","internalName":"delta","declarationFragments":[{"kind":"identifier","spelling":"delta"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"}]}],"returns":[{"kind":"text","spelling":"()"}]},"declarationFragments":[{"kind":"keyword","spelling":"mutating"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"expand"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"by"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"delta"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":")"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":85,"character":25}}},{"kind":{"identifier":"swift.func.op","displayName":"Operator"},"identifier":{"precise":"s:9SwiftDemo4RingV1poiyA2C_ACtFZ","interfaceLanguage":"swift"},"pathComponents":["Ring","+(_:_:)"],"names":{"title":"+(_:_:)","subHeading":[{"kind":"keyword","spelling":"static"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"+"},{"kind":"text","spelling":" "},{"kind":"text","spelling":"("},{"kind":"typeIdentifier","spelling":"Ring","preciseIdentifier":"s:9SwiftDemo4RingV"},{"kind":"text","spelling":", "},{"kind":"typeIdentifier","spelling":"Ring","preciseIdentifier":"s:9SwiftDemo4RingV"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"Ring","preciseIdentifier":"s:9SwiftDemo4RingV"}]},"functionSignature":{"parameters":[{"name":"lhs","declarationFragments":[{"kind":"identifier","spelling":"lhs"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Ring","preciseIdentifier":"s:9SwiftDemo4RingV"}]},{"name":"rhs","declarationFragments":[{"kind":"identifier","spelling":"rhs"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Ring","preciseIdentifier":"s:9SwiftDemo4RingV"}]}],"returns":[{"kind":"typeIdentifier","spelling":"Ring","preciseIdentifier":"s:9SwiftDemo4RingV"}]},"declarationFragments":[{"kind":"keyword","spelling":"static"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"+"},{"kind":"text","spelling":" "},{"kind":"text","spelling":"("},{"kind":"internalParam","spelling":"lhs"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Ring","preciseIdentifier":"s:9SwiftDemo4RingV"},{"kind":"text","spelling":", "},{"kind":"internalParam","spelling":"rhs"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Ring","preciseIdentifier":"s:9SwiftDemo4RingV"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"Ring","preciseIdentifier":"s:9SwiftDemo4RingV"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":90,"character":23}}},{"kind":{"identifier":"swift.class","displayName":"Class"},"identifier":{"precise":"s:9SwiftDemo7CounterC","interfaceLanguage":"swift"},"pathComponents":["Counter"],"names":{"title":"Counter","navigator":[{"kind":"identifier","spelling":"Counter"}],"subHeading":[{"kind":"keyword","spelling":"actor"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Counter"}]},"declarationFragments":[{"kind":"keyword","spelling":"actor"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Counter"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":95,"character":13}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:ScA12_ConcurrencyE18withSerialExecutoryqd__qd__Scf_pqd_0_YKXEqd_0_YKs5ErrorRd_0_Ri_d__r0_lF::SYNTHESIZED::s:9SwiftDemo7CounterC","interfaceLanguage":"swift"},"pathComponents":["Counter","withSerialExecutor(_:)"],"names":{"title":"withSerialExecutor(_:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"withSerialExecutor"},{"kind":"text","spelling":"<"},{"kind":"genericParameter","spelling":"T"},{"kind":"text","spelling":", "},{"kind":"genericParameter","spelling":"E"},{"kind":"text","spelling":">((any "},{"kind":"typeIdentifier","spelling":"SerialExecutor","preciseIdentifier":"s:Scf"},{"kind":"text","spelling":") "},{"kind":"keyword","spelling":"throws"},{"kind":"text","spelling":"("},{"kind":"typeIdentifier","spelling":"E"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"T"},{"kind":"text","spelling":") "},{"kind":"keyword","spelling":"throws"},{"kind":"text","spelling":"("},{"kind":"typeIdentifier","spelling":"E"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"T"}]},"docComment":{"module":"_Concurrency","lines":[{"text":"Perform an operation with the actor's ``SerialExecutor``."},{"text":""},{"text":"This converts the actor's ``Actor/unownedExecutor`` to a ``SerialExecutor`` while"},{"text":"retaining the actor for the duration of the operation. This is to ensure the lifetime"},{"text":"of the executor while performing the operation."}]},"functionSignature":{"parameters":[{"name":"operation","declarationFragments":[{"kind":"identifier","spelling":"operation"},{"kind":"text","spelling":": (any "},{"kind":"typeIdentifier","spelling":"SerialExecutor","preciseIdentifier":"s:Scf"},{"kind":"text","spelling":") "},{"kind":"keyword","spelling":"throws"},{"kind":"text","spelling":"("},{"kind":"typeIdentifier","spelling":"E"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"T"}]}],"returns":[{"kind":"typeIdentifier","spelling":"T"}]},"swiftGenerics":{"parameters":[{"name":"T","index":0,"depth":1},{"name":"E","index":1,"depth":1}],"constraints":[{"kind":"conformance","lhs":"E","rhs":"Error","rhsPrecise":"s:s5ErrorP"}]},"swiftExtension":{"extendedModule":"_Concurrency","typeKind":"swift.protocol"},"declarationFragments":[{"kind":"attribute","spelling":"nonisolated"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"withSerialExecutor"},{"kind":"text","spelling":"<"},{"kind":"genericParameter","spelling":"T"},{"kind":"text","spelling":", "},{"kind":"genericParameter","spelling":"E"},{"kind":"text","spelling":">("},{"kind":"externalParam","spelling":"_"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"operation"},{"kind":"text","spelling":": (any "},{"kind":"typeIdentifier","spelling":"SerialExecutor","preciseIdentifier":"s:Scf"},{"kind":"text","spelling":") "},{"kind":"keyword","spelling":"throws"},{"kind":"text","spelling":"("},{"kind":"typeIdentifier","spelling":"E"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"T"},{"kind":"text","spelling":") "},{"kind":"keyword","spelling":"throws"},{"kind":"text","spelling":"("},{"kind":"typeIdentifier","spelling":"E"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"T"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"where"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"E"},{"kind":"text","spelling":" : "},{"kind":"typeIdentifier","spelling":"Error","preciseIdentifier":"s:s5ErrorP"},{"kind":"text","spelling":", "},{"kind":"typeIdentifier","spelling":"T"},{"kind":"text","spelling":" : ~Copyable"}],"accessLevel":"public","availability":[{"domain":"iOS","introduced":{"major":13,"minor":0}},{"domain":"macOS","introduced":{"major":10,"minor":15}},{"domain":"tvOS","introduced":{"major":13,"minor":0}},{"domain":"watchOS","introduced":{"major":6,"minor":0}}]},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:ScA12_ConcurrencyE18withSerialExecutoryqd__qd__Scf_pYaqd_0_YKYCXEYaqd_0_YKs5ErrorRd_0_Ri_d__r0_lF::SYNTHESIZED::s:9SwiftDemo7CounterC","interfaceLanguage":"swift"},"pathComponents":["Counter","withSerialExecutor(_:)"],"names":{"title":"withSerialExecutor(_:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"withSerialExecutor"},{"kind":"text","spelling":"<"},{"kind":"genericParameter","spelling":"T"},{"kind":"text","spelling":", "},{"kind":"genericParameter","spelling":"E"},{"kind":"text","spelling":">("},{"kind":"keyword","spelling":"nonisolated(nonsending)"},{"kind":"text","spelling":" (any "},{"kind":"typeIdentifier","spelling":"SerialExecutor","preciseIdentifier":"s:Scf"},{"kind":"text","spelling":") "},{"kind":"keyword","spelling":"async"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"throws"},{"kind":"text","spelling":"("},{"kind":"typeIdentifier","spelling":"E"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"T"},{"kind":"text","spelling":") "},{"kind":"keyword","spelling":"async"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"throws"},{"kind":"text","spelling":"("},{"kind":"typeIdentifier","spelling":"E"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"T"}]},"docComment":{"module":"_Concurrency","lines":[{"text":"Perform an operation with the actor's ``SerialExecutor``."},{"text":""},{"text":"This converts the actor's ``Actor/unownedExecutor`` to a ``SerialExecutor`` while"},{"text":"retaining the actor for the duration of the operation. This is to ensure the lifetime"},{"text":"of the executor while performing the operation."}]},"functionSignature":{"parameters":[{"name":"operation","declarationFragments":[{"kind":"identifier","spelling":"operation"},{"kind":"text","spelling":": (any "},{"kind":"typeIdentifier","spelling":"SerialExecutor","preciseIdentifier":"s:Scf"},{"kind":"text","spelling":") "},{"kind":"keyword","spelling":"async"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"throws"},{"kind":"text","spelling":"("},{"kind":"typeIdentifier","spelling":"E"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"T"}]}],"returns":[{"kind":"typeIdentifier","spelling":"T"}]},"swiftGenerics":{"parameters":[{"name":"T","index":0,"depth":1},{"name":"E","index":1,"depth":1}],"constraints":[{"kind":"conformance","lhs":"E","rhs":"Error","rhsPrecise":"s:s5ErrorP"}]},"swiftExtension":{"extendedModule":"_Concurrency","typeKind":"swift.protocol"},"declarationFragments":[{"kind":"attribute","spelling":"nonisolated"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"withSerialExecutor"},{"kind":"text","spelling":"<"},{"kind":"genericParameter","spelling":"T"},{"kind":"text","spelling":", "},{"kind":"genericParameter","spelling":"E"},{"kind":"text","spelling":">("},{"kind":"externalParam","spelling":"_"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"operation"},{"kind":"text","spelling":": "},{"kind":"keyword","spelling":"nonisolated(nonsending)"},{"kind":"text","spelling":" (any "},{"kind":"typeIdentifier","spelling":"SerialExecutor","preciseIdentifier":"s:Scf"},{"kind":"text","spelling":") "},{"kind":"keyword","spelling":"async"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"throws"},{"kind":"text","spelling":"("},{"kind":"typeIdentifier","spelling":"E"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"T"},{"kind":"text","spelling":") "},{"kind":"keyword","spelling":"async"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"throws"},{"kind":"text","spelling":"("},{"kind":"typeIdentifier","spelling":"E"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"T"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"where"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"E"},{"kind":"text","spelling":" : "},{"kind":"typeIdentifier","spelling":"Error","preciseIdentifier":"s:s5ErrorP"},{"kind":"text","spelling":", "},{"kind":"typeIdentifier","spelling":"T"},{"kind":"text","spelling":" : ~Copyable"}],"accessLevel":"public","availability":[{"domain":"iOS","introduced":{"major":13,"minor":0}},{"domain":"macOS","introduced":{"major":10,"minor":15}},{"domain":"tvOS","introduced":{"major":13,"minor":0}},{"domain":"watchOS","introduced":{"major":6,"minor":0}}]},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:ScA12_ConcurrencyE20preconditionIsolated_4file4lineySSyXK_s12StaticStringVSutF::SYNTHESIZED::s:9SwiftDemo7CounterC","interfaceLanguage":"swift"},"pathComponents":["Counter","preconditionIsolated(_:file:line:)"],"names":{"title":"preconditionIsolated(_:file:line:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"preconditionIsolated"},{"kind":"text","spelling":"("},{"kind":"attribute","spelling":"@autoclosure "},{"kind":"text","spelling":"() -> "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"file"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"StaticString","preciseIdentifier":"s:s12StaticStringV"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"line"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"UInt","preciseIdentifier":"s:Su"},{"kind":"text","spelling":")"}]},"docComment":{"module":"_Concurrency","lines":[{"text":"Stops program execution if the current task is not executing on this"},{"text":"actor's serial executor."},{"text":""},{"text":"This function's effect varies depending on the build flag used:"},{"text":""},{"text":"* In playgrounds and `-Onone` builds (the default for Xcode's Debug"},{"text":" configuration), stops program execution in a debuggable state after"},{"text":" printing `message`."},{"text":""},{"text":"* In `-O` builds (the default for Xcode's Release configuration), stops"},{"text":" program execution."},{"text":""},{"text":"- Note: Because this check is performed against the actor's serial executor,"},{"text":" if another actor uses the same serial executor--by using"},{"text":" that actor's serial executor as its own ``Actor/unownedExecutor``--this"},{"text":" check will succeed. From a concurrency safety perspective, the"},{"text":" serial executor guarantees mutual exclusion of those two actors."},{"text":""},{"text":"- Parameters:"},{"text":" - message: The message to print if the assertion fails."},{"text":" - file: The file name to print if the assertion fails. The default is"},{"text":" where this method was called."},{"text":" - line: The line number to print if the assertion fails The default is"},{"text":" where this method was called."}]},"functionSignature":{"parameters":[{"name":"message","declarationFragments":[{"kind":"identifier","spelling":"message"},{"kind":"text","spelling":": () -> "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},{"name":"file","declarationFragments":[{"kind":"identifier","spelling":"file"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"StaticString","preciseIdentifier":"s:s12StaticStringV"}]},{"name":"line","declarationFragments":[{"kind":"identifier","spelling":"line"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"UInt","preciseIdentifier":"s:Su"}]}],"returns":[{"kind":"text","spelling":"()"}]},"swiftExtension":{"extendedModule":"_Concurrency","typeKind":"swift.protocol"},"declarationFragments":[{"kind":"text","spelling":"@backDeployed(before: macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0)\n"},{"kind":"attribute","spelling":"nonisolated"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"preconditionIsolated"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"_"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"message"},{"kind":"text","spelling":": "},{"kind":"attribute","spelling":"@autoclosure "},{"kind":"text","spelling":"() -> "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":" = String(), "},{"kind":"externalParam","spelling":"file"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"StaticString","preciseIdentifier":"s:s12StaticStringV"},{"kind":"text","spelling":" = "},{"kind":"keyword","spelling":"#fileID"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"line"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"UInt","preciseIdentifier":"s:Su"},{"kind":"text","spelling":" = "},{"kind":"keyword","spelling":"#line"},{"kind":"text","spelling":")"}],"accessLevel":"public","availability":[{"domain":"iOS","introduced":{"major":13,"minor":0}},{"domain":"macOS","introduced":{"major":10,"minor":15}},{"domain":"tvOS","introduced":{"major":13,"minor":0}},{"domain":"watchOS","introduced":{"major":6,"minor":0}}]},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:ScA12_ConcurrencyE14assertIsolated_4file4lineySSyXK_s12StaticStringVSutF::SYNTHESIZED::s:9SwiftDemo7CounterC","interfaceLanguage":"swift"},"pathComponents":["Counter","assertIsolated(_:file:line:)"],"names":{"title":"assertIsolated(_:file:line:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"assertIsolated"},{"kind":"text","spelling":"("},{"kind":"attribute","spelling":"@autoclosure "},{"kind":"text","spelling":"() -> "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"file"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"StaticString","preciseIdentifier":"s:s12StaticStringV"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"line"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"UInt","preciseIdentifier":"s:Su"},{"kind":"text","spelling":")"}]},"docComment":{"module":"_Concurrency","lines":[{"text":"Stops program execution if the current task is not executing on this"},{"text":"actor's serial executor."},{"text":""},{"text":"This function's effect varies depending on the build flag used:"},{"text":""},{"text":"* In playgrounds and `-Onone` builds (the default for Xcode's Debug"},{"text":" configuration), stops program execution in a debuggable state after"},{"text":" printing `message`."},{"text":""},{"text":"* In `-O` builds (the default for Xcode's Release configuration),"},{"text":" the isolation check is not performed and there are no effects."},{"text":""},{"text":"- Note: This check is performed against the actor's serial executor,"},{"text":" meaning that / if another actor uses the same serial executor--by using"},{"text":" that actor's serial executor as its own ``Actor/unownedExecutor``--this"},{"text":" check will succeed , as from a concurrency safety perspective, the"},{"text":" serial executor guarantees mutual exclusion of those two actors."},{"text":""},{"text":"- Parameters:"},{"text":" - message: The message to print if the assertion fails."},{"text":" - file: The file name to print if the assertion fails. The default is"},{"text":" where this method was called."},{"text":" - line: The line number to print if the assertion fails The default is"},{"text":" where this method was called."}]},"functionSignature":{"parameters":[{"name":"message","declarationFragments":[{"kind":"identifier","spelling":"message"},{"kind":"text","spelling":": () -> "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},{"name":"file","declarationFragments":[{"kind":"identifier","spelling":"file"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"StaticString","preciseIdentifier":"s:s12StaticStringV"}]},{"name":"line","declarationFragments":[{"kind":"identifier","spelling":"line"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"UInt","preciseIdentifier":"s:Su"}]}],"returns":[{"kind":"text","spelling":"()"}]},"swiftExtension":{"extendedModule":"_Concurrency","typeKind":"swift.protocol"},"declarationFragments":[{"kind":"text","spelling":"@backDeployed(before: macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0)\n"},{"kind":"attribute","spelling":"nonisolated"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"assertIsolated"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"_"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"message"},{"kind":"text","spelling":": "},{"kind":"attribute","spelling":"@autoclosure "},{"kind":"text","spelling":"() -> "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":" = String(), "},{"kind":"externalParam","spelling":"file"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"StaticString","preciseIdentifier":"s:s12StaticStringV"},{"kind":"text","spelling":" = "},{"kind":"keyword","spelling":"#fileID"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"line"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"UInt","preciseIdentifier":"s:Su"},{"kind":"text","spelling":" = "},{"kind":"keyword","spelling":"#line"},{"kind":"text","spelling":")"}],"accessLevel":"public","availability":[{"domain":"iOS","introduced":{"major":13,"minor":0}},{"domain":"macOS","introduced":{"major":10,"minor":15}},{"domain":"tvOS","introduced":{"major":13,"minor":0}},{"domain":"watchOS","introduced":{"major":6,"minor":0}}]},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:ScA12_ConcurrencyE14assumeIsolated_4file4lineqd__qd__xYiKXE_s12StaticStringVSutKs8SendableRd__lF::SYNTHESIZED::s:9SwiftDemo7CounterC","interfaceLanguage":"swift"},"pathComponents":["Counter","assumeIsolated(_:file:line:)"],"names":{"title":"assumeIsolated(_:file:line:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"assumeIsolated"},{"kind":"text","spelling":"<"},{"kind":"genericParameter","spelling":"T"},{"kind":"text","spelling":">(("},{"kind":"keyword","spelling":"isolated"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"Self"},{"kind":"text","spelling":") "},{"kind":"keyword","spelling":"throws"},{"kind":"text","spelling":" -> "},{"kind":"typeIdentifier","spelling":"T"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"file"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"StaticString","preciseIdentifier":"s:s12StaticStringV"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"line"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"UInt","preciseIdentifier":"s:Su"},{"kind":"text","spelling":") "},{"kind":"keyword","spelling":"rethrows"},{"kind":"text","spelling":" -> "},{"kind":"typeIdentifier","spelling":"T"}]},"docComment":{"module":"_Concurrency","lines":[{"text":"Assume that the current task is executing on this actor's serial executor,"},{"text":"or stop program execution otherwise."},{"text":""},{"text":"You call this method to *assume and verify* that the currently"},{"text":"executing synchronous function is actually executing on the serial"},{"text":"executor of this actor."},{"text":""},{"text":"If that is the case, the operation is invoked with an `isolated` version"},{"text":"of the actor, allowing synchronous access to actor local state without"},{"text":"hopping through asynchronous boundaries."},{"text":""},{"text":"If the current context is not running on the actor's serial executor, or"},{"text":"if the actor is a reference to a remote actor, this method will crash"},{"text":"with a fatal error (similar to ``preconditionIsolated(_:file:line:)``)."},{"text":""},{"text":"Note that this check is performed against the passed in actor's serial"},{"text":"executor, meaning that if another actor uses the same serial executor--by"},{"text":"using that actor's ``Actor/unownedExecutor`` as its own"},{"text":"``Actor/unownedExecutor``--this check will succeed, as from a concurrency"},{"text":"safety perspective, the serial executor guarantees mutual exclusion of"},{"text":"those two actors."},{"text":""},{"text":"This method can only be used from synchronous functions, as asynchronous"},{"text":"functions should instead perform a normal method call to the actor, which"},{"text":"will hop task execution to the target actor if necessary."},{"text":""},{"text":"- Note: This check is performed against the actor's serial executor,"},{"text":" meaning that / if another actor uses the same serial executor--by using"},{"text":" another actor's executor as its own ``Actor/unownedExecutor``"},{"text":" --this check will succeed , as from a concurrency safety perspective,"},{"text":" the serial executor guarantees mutual exclusion of those two actors."},{"text":""},{"text":"- Parameters:"},{"text":" - operation: the operation that will be executed if the current context"},{"text":" is executing on the actors serial executor."},{"text":" - file: The file name to print if the assertion fails. The default is"},{"text":" where this method was called."},{"text":" - line: The line number to print if the assertion fails The default is"},{"text":" where this method was called."},{"text":"- Returns: the return value of the `operation`"},{"text":"- Throws: rethrows the `Error` thrown by the operation if it threw"}]},"functionSignature":{"parameters":[{"name":"operation","declarationFragments":[{"kind":"identifier","spelling":"operation"},{"kind":"text","spelling":": ("},{"kind":"keyword","spelling":"isolated"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"Self"},{"kind":"text","spelling":") "},{"kind":"keyword","spelling":"throws"},{"kind":"text","spelling":" -> "},{"kind":"typeIdentifier","spelling":"T"}]},{"name":"file","declarationFragments":[{"kind":"identifier","spelling":"file"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"StaticString","preciseIdentifier":"s:s12StaticStringV"}]},{"name":"line","declarationFragments":[{"kind":"identifier","spelling":"line"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"UInt","preciseIdentifier":"s:Su"}]}],"returns":[{"kind":"typeIdentifier","spelling":"T"}]},"swiftGenerics":{"parameters":[{"name":"T","index":0,"depth":1}],"constraints":[{"kind":"conformance","lhs":"T","rhs":"Sendable","rhsPrecise":"s:s8SendableP"}]},"swiftExtension":{"extendedModule":"_Concurrency","typeKind":"swift.protocol"},"declarationFragments":[{"kind":"attribute","spelling":"nonisolated"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"assumeIsolated"},{"kind":"text","spelling":"<"},{"kind":"genericParameter","spelling":"T"},{"kind":"text","spelling":">("},{"kind":"externalParam","spelling":"_"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"operation"},{"kind":"text","spelling":": ("},{"kind":"keyword","spelling":"isolated"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"Self"},{"kind":"text","spelling":") "},{"kind":"keyword","spelling":"throws"},{"kind":"text","spelling":" -> "},{"kind":"typeIdentifier","spelling":"T"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"file"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"StaticString","preciseIdentifier":"s:s12StaticStringV"},{"kind":"text","spelling":" = "},{"kind":"keyword","spelling":"#fileID"},{"kind":"text","spelling":", "},{"kind":"externalParam","spelling":"line"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"UInt","preciseIdentifier":"s:Su"},{"kind":"text","spelling":" = "},{"kind":"keyword","spelling":"#line"},{"kind":"text","spelling":") "},{"kind":"keyword","spelling":"rethrows"},{"kind":"text","spelling":" -> "},{"kind":"typeIdentifier","spelling":"T"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"where"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"T"},{"kind":"text","spelling":" : "},{"kind":"typeIdentifier","spelling":"Sendable","preciseIdentifier":"s:s8SendableP"}],"accessLevel":"public","availability":[{"domain":"iOS","introduced":{"major":13,"minor":0}},{"domain":"macOS","introduced":{"major":10,"minor":15}},{"domain":"tvOS","introduced":{"major":13,"minor":0}},{"domain":"watchOS","introduced":{"major":6,"minor":0}}]},{"kind":{"identifier":"swift.property","displayName":"Instance Property"},"identifier":{"precise":"s:9SwiftDemo7CounterC5valueSivp","interfaceLanguage":"swift"},"pathComponents":["Counter","value"],"names":{"title":"value","subHeading":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"value"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"}]},"declarationFragments":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"value"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":" { get }"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":96,"character":28}}},{"kind":{"identifier":"swift.init","displayName":"Initializer"},"identifier":{"precise":"s:9SwiftDemo7CounterCACycfc","interfaceLanguage":"swift"},"pathComponents":["Counter","init()"],"names":{"title":"init()","subHeading":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"()"}]},"functionSignature":{},"declarationFragments":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"()"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":97,"character":11}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo7CounterC9incrementSiyF","interfaceLanguage":"swift"},"pathComponents":["Counter","increment()"],"names":{"title":"increment()","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"increment"},{"kind":"text","spelling":"() -> "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"}]},"functionSignature":{"returns":[{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"increment"},{"kind":"text","spelling":"() -> "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":98,"character":16}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo7CounterC5labelSSyF","interfaceLanguage":"swift"},"pathComponents":["Counter","label()"],"names":{"title":"label()","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"label"},{"kind":"text","spelling":"() -> "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},"functionSignature":{"returns":[{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},"declarationFragments":[{"kind":"attribute","spelling":"nonisolated"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"label"},{"kind":"text","spelling":"() -> "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":102,"character":28}}},{"kind":{"identifier":"swift.class","displayName":"Class"},"identifier":{"precise":"s:9SwiftDemo6CanvasC","interfaceLanguage":"swift"},"pathComponents":["Canvas"],"names":{"title":"Canvas","navigator":[{"kind":"identifier","spelling":"Canvas"}],"subHeading":[{"kind":"keyword","spelling":"class"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Canvas"}]},"declarationFragments":[{"kind":"attribute","spelling":"@"},{"kind":"attribute","spelling":"MainActor","preciseIdentifier":"s:ScM"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"final"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"class"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Canvas"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":106,"character":19}}},{"kind":{"identifier":"swift.init","displayName":"Initializer"},"identifier":{"precise":"s:9SwiftDemo6CanvasCACycfc","interfaceLanguage":"swift"},"pathComponents":["Canvas","init()"],"names":{"title":"init()","subHeading":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"()"}]},"functionSignature":{},"declarationFragments":[{"kind":"attribute","spelling":"@"},{"kind":"attribute","spelling":"MainActor","preciseIdentifier":"s:ScM"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"()"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":107,"character":11}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo6CanvasC4drawyyAA5Shape_pF","interfaceLanguage":"swift"},"pathComponents":["Canvas","draw(_:)"],"names":{"title":"draw(_:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"draw"},{"kind":"text","spelling":"("},{"kind":"keyword","spelling":"any"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"Shape","preciseIdentifier":"s:9SwiftDemo5ShapeP"},{"kind":"text","spelling":")"}]},"functionSignature":{"parameters":[{"name":"shape","declarationFragments":[{"kind":"identifier","spelling":"shape"},{"kind":"text","spelling":": "},{"kind":"keyword","spelling":"any"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"Shape","preciseIdentifier":"s:9SwiftDemo5ShapeP"}]}],"returns":[{"kind":"text","spelling":"()"}]},"declarationFragments":[{"kind":"attribute","spelling":"@"},{"kind":"attribute","spelling":"MainActor","preciseIdentifier":"s:ScM"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"draw"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"_"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"shape"},{"kind":"text","spelling":": "},{"kind":"keyword","spelling":"any"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"Shape","preciseIdentifier":"s:9SwiftDemo5ShapeP"},{"kind":"text","spelling":")"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":108,"character":16}}},{"kind":{"identifier":"swift.class","displayName":"Class"},"identifier":{"precise":"s:9SwiftDemo6LoaderC","interfaceLanguage":"swift"},"pathComponents":["Loader"],"names":{"title":"Loader","navigator":[{"kind":"identifier","spelling":"Loader"}],"subHeading":[{"kind":"keyword","spelling":"class"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Loader"}]},"declarationFragments":[{"kind":"keyword","spelling":"final"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"class"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Loader"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":111,"character":19}}},{"kind":{"identifier":"swift.init","displayName":"Initializer"},"identifier":{"precise":"s:9SwiftDemo6LoaderCACycfc","interfaceLanguage":"swift"},"pathComponents":["Loader","init()"],"names":{"title":"init()","subHeading":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"()"}]},"functionSignature":{},"declarationFragments":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"()"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":112,"character":11}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo6LoaderC4load4path10Foundation4DataVSS_tKF","interfaceLanguage":"swift"},"pathComponents":["Loader","load(path:)"],"names":{"title":"load(path:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"load"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"path"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":") "},{"kind":"keyword","spelling":"throws"},{"kind":"text","spelling":" -> "},{"kind":"typeIdentifier","spelling":"Data","preciseIdentifier":"s:10Foundation4DataV"}]},"functionSignature":{"parameters":[{"name":"path","declarationFragments":[{"kind":"identifier","spelling":"path"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]}],"returns":[{"kind":"typeIdentifier","spelling":"Data","preciseIdentifier":"s:10Foundation4DataV"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"load"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"path"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":") "},{"kind":"keyword","spelling":"throws"},{"kind":"text","spelling":" -> "},{"kind":"typeIdentifier","spelling":"Data","preciseIdentifier":"s:10Foundation4DataV"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":114,"character":16}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo6LoaderC5fetch3urlSS10Foundation3URLV_tYaKF","interfaceLanguage":"swift"},"pathComponents":["Loader","fetch(url:)"],"names":{"title":"fetch(url:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"fetch"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"url"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"URL","preciseIdentifier":"s:10Foundation3URLV"},{"kind":"text","spelling":") "},{"kind":"keyword","spelling":"async"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"throws"},{"kind":"text","spelling":" -> "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},"functionSignature":{"parameters":[{"name":"url","declarationFragments":[{"kind":"identifier","spelling":"url"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"URL","preciseIdentifier":"s:10Foundation3URLV"}]}],"returns":[{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"fetch"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"url"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"URL","preciseIdentifier":"s:10Foundation3URLV"},{"kind":"text","spelling":") "},{"kind":"keyword","spelling":"async"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"throws"},{"kind":"text","spelling":" -> "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":115,"character":16}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo6LoaderC4wait7secondsySd_tYaF","interfaceLanguage":"swift"},"pathComponents":["Loader","wait(seconds:)"],"names":{"title":"wait(seconds:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"wait"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"seconds"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":") "},{"kind":"keyword","spelling":"async"}]},"functionSignature":{"parameters":[{"name":"seconds","declarationFragments":[{"kind":"identifier","spelling":"seconds"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"}]}],"returns":[{"kind":"text","spelling":"()"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"wait"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"seconds"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":") "},{"kind":"keyword","spelling":"async"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":116,"character":16}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo6LoaderC9transformyxxAA5ShapeRzlF","interfaceLanguage":"swift"},"pathComponents":["Loader","transform(_:)"],"names":{"title":"transform(_:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"transform"},{"kind":"text","spelling":"<"},{"kind":"genericParameter","spelling":"T"},{"kind":"text","spelling":">("},{"kind":"typeIdentifier","spelling":"T","preciseIdentifier":"s:9SwiftDemo6LoaderC9transformyxxAA5ShapeRzlF1TL_xmfp"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"T","preciseIdentifier":"s:9SwiftDemo6LoaderC9transformyxxAA5ShapeRzlF1TL_xmfp"}]},"functionSignature":{"parameters":[{"name":"shape","declarationFragments":[{"kind":"identifier","spelling":"shape"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"T","preciseIdentifier":"s:9SwiftDemo6LoaderC9transformyxxAA5ShapeRzlF1TL_xmfp"}]}],"returns":[{"kind":"typeIdentifier","spelling":"T"}]},"swiftGenerics":{"parameters":[{"name":"T","index":0,"depth":0}],"constraints":[{"kind":"conformance","lhs":"T","rhs":"Shape","rhsPrecise":"s:9SwiftDemo5ShapeP"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"transform"},{"kind":"text","spelling":"<"},{"kind":"genericParameter","spelling":"T"},{"kind":"text","spelling":">("},{"kind":"externalParam","spelling":"_"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"shape"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"T","preciseIdentifier":"s:9SwiftDemo6LoaderC9transformyxxAA5ShapeRzlF1TL_xmfp"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"T","preciseIdentifier":"s:9SwiftDemo6LoaderC9transformyxxAA5ShapeRzlF1TL_xmfp"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"where"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"T"},{"kind":"text","spelling":" : "},{"kind":"typeIdentifier","spelling":"Shape","preciseIdentifier":"s:9SwiftDemo5ShapeP"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":118,"character":16}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo6LoaderC5first2ofxSgSayxG_tlF","interfaceLanguage":"swift"},"pathComponents":["Loader","first(of:)"],"names":{"title":"first(of:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"first"},{"kind":"text","spelling":"<"},{"kind":"genericParameter","spelling":"Element"},{"kind":"text","spelling":">("},{"kind":"externalParam","spelling":"of"},{"kind":"text","spelling":": ["},{"kind":"typeIdentifier","spelling":"Element","preciseIdentifier":"s:9SwiftDemo6LoaderC5first2ofxSgSayxG_tlF7ElementL_xmfp"},{"kind":"text","spelling":"]) -> "},{"kind":"typeIdentifier","spelling":"Element","preciseIdentifier":"s:9SwiftDemo6LoaderC5first2ofxSgSayxG_tlF7ElementL_xmfp"},{"kind":"text","spelling":"?"}]},"functionSignature":{"parameters":[{"name":"of","internalName":"items","declarationFragments":[{"kind":"identifier","spelling":"items"},{"kind":"text","spelling":": ["},{"kind":"typeIdentifier","spelling":"Element","preciseIdentifier":"s:9SwiftDemo6LoaderC5first2ofxSgSayxG_tlF7ElementL_xmfp"},{"kind":"text","spelling":"]"}]}],"returns":[{"kind":"typeIdentifier","spelling":"Element"},{"kind":"text","spelling":"?"}]},"swiftGenerics":{"parameters":[{"name":"Element","index":0,"depth":0}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"first"},{"kind":"text","spelling":"<"},{"kind":"genericParameter","spelling":"Element"},{"kind":"text","spelling":">("},{"kind":"externalParam","spelling":"of"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"items"},{"kind":"text","spelling":": ["},{"kind":"typeIdentifier","spelling":"Element","preciseIdentifier":"s:9SwiftDemo6LoaderC5first2ofxSgSayxG_tlF7ElementL_xmfp"},{"kind":"text","spelling":"]) -> "},{"kind":"typeIdentifier","spelling":"Element","preciseIdentifier":"s:9SwiftDemo6LoaderC5first2ofxSgSayxG_tlF7ElementL_xmfp"},{"kind":"text","spelling":"?"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":119,"character":16}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo6LoaderC14withCompletionyyys6ResultOySSAA10ShapeErrorOGcF","interfaceLanguage":"swift"},"pathComponents":["Loader","withCompletion(_:)"],"names":{"title":"withCompletion(_:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"withCompletion"},{"kind":"text","spelling":"(("},{"kind":"typeIdentifier","spelling":"Result","preciseIdentifier":"s:s6ResultO"},{"kind":"text","spelling":"<"},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":", "},{"kind":"typeIdentifier","spelling":"ShapeError","preciseIdentifier":"s:9SwiftDemo10ShapeErrorO"},{"kind":"text","spelling":">) -> "},{"kind":"typeIdentifier","spelling":"Void","preciseIdentifier":"s:s4Voida"},{"kind":"text","spelling":")"}]},"functionSignature":{"parameters":[{"name":"completion","declarationFragments":[{"kind":"identifier","spelling":"completion"},{"kind":"text","spelling":": "},{"kind":"attribute","spelling":"@escaping"},{"kind":"text","spelling":" ("},{"kind":"typeIdentifier","spelling":"Result","preciseIdentifier":"s:s6ResultO"},{"kind":"text","spelling":"<"},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":", "},{"kind":"typeIdentifier","spelling":"ShapeError","preciseIdentifier":"s:9SwiftDemo10ShapeErrorO"},{"kind":"text","spelling":">) -> "},{"kind":"typeIdentifier","spelling":"Void","preciseIdentifier":"s:s4Voida"}]}],"returns":[{"kind":"text","spelling":"()"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"withCompletion"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"_"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"completion"},{"kind":"text","spelling":": "},{"kind":"attribute","spelling":"@escaping"},{"kind":"text","spelling":" ("},{"kind":"typeIdentifier","spelling":"Result","preciseIdentifier":"s:s6ResultO"},{"kind":"text","spelling":"<"},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":", "},{"kind":"typeIdentifier","spelling":"ShapeError","preciseIdentifier":"s:9SwiftDemo10ShapeErrorO"},{"kind":"text","spelling":">) -> "},{"kind":"typeIdentifier","spelling":"Void","preciseIdentifier":"s:s4Voida"},{"kind":"text","spelling":")"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":121,"character":16}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo6LoaderC4eachyyySiXEF","interfaceLanguage":"swift"},"pathComponents":["Loader","each(_:)"],"names":{"title":"each(_:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"each"},{"kind":"text","spelling":"(("},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"Void","preciseIdentifier":"s:s4Voida"},{"kind":"text","spelling":")"}]},"functionSignature":{"parameters":[{"name":"body","declarationFragments":[{"kind":"identifier","spelling":"body"},{"kind":"text","spelling":": ("},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"Void","preciseIdentifier":"s:s4Voida"}]}],"returns":[{"kind":"text","spelling":"()"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"each"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"_"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"body"},{"kind":"text","spelling":": ("},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"Void","preciseIdentifier":"s:s4Voida"},{"kind":"text","spelling":")"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":122,"character":16}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo6LoaderC6lookup5table3keySiSgSDySSSiG_SStF","interfaceLanguage":"swift"},"pathComponents":["Loader","lookup(table:key:)"],"names":{"title":"lookup(table:key:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"lookup"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"table"},{"kind":"text","spelling":": ["},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":" : "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":"], "},{"kind":"externalParam","spelling":"key"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":"?"}]},"functionSignature":{"parameters":[{"name":"table","declarationFragments":[{"kind":"identifier","spelling":"table"},{"kind":"text","spelling":": ["},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":" : "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":"]"}]},{"name":"key","declarationFragments":[{"kind":"identifier","spelling":"key"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]}],"returns":[{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":"?"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"lookup"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"table"},{"kind":"text","spelling":": ["},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":" : "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":"], "},{"kind":"externalParam","spelling":"key"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":"?"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":124,"character":16}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo6LoaderC6updateyyAA5PointVzF","interfaceLanguage":"swift"},"pathComponents":["Loader","update(_:)"],"names":{"title":"update(_:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"update"},{"kind":"text","spelling":"("},{"kind":"keyword","spelling":"inout"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"Point","preciseIdentifier":"s:9SwiftDemo5PointV"},{"kind":"text","spelling":")"}]},"functionSignature":{"parameters":[{"name":"point","declarationFragments":[{"kind":"identifier","spelling":"point"},{"kind":"text","spelling":": "},{"kind":"keyword","spelling":"inout"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"Point","preciseIdentifier":"s:9SwiftDemo5PointV"}]}],"returns":[{"kind":"text","spelling":"()"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"update"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"_"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"point"},{"kind":"text","spelling":": "},{"kind":"keyword","spelling":"inout"},{"kind":"text","spelling":" "},{"kind":"typeIdentifier","spelling":"Point","preciseIdentifier":"s:9SwiftDemo5PointV"},{"kind":"text","spelling":")"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":126,"character":16}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo6LoaderC10modernOnlyyyF","interfaceLanguage":"swift"},"pathComponents":["Loader","modernOnly()"],"names":{"title":"modernOnly()","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"modernOnly"},{"kind":"text","spelling":"()"}]},"functionSignature":{"returns":[{"kind":"text","spelling":"()"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"modernOnly"},{"kind":"text","spelling":"()"}],"accessLevel":"public","availability":[{"domain":"iOS","introduced":{"major":16,"minor":0}}],"location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":129,"character":16}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo6LoaderC11legacyFetchyyF","interfaceLanguage":"swift"},"pathComponents":["Loader","legacyFetch()"],"names":{"title":"legacyFetch()","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"legacyFetch"},{"kind":"text","spelling":"()"}]},"functionSignature":{"returns":[{"kind":"text","spelling":"()"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"legacyFetch"},{"kind":"text","spelling":"()"}],"accessLevel":"public","availability":[{"domain":"*","message":"Use fetch(url:) instead","isUnconditionallyDeprecated":true}],"location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":132,"character":16}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo6LoaderC8oldFetchyyF","interfaceLanguage":"swift"},"pathComponents":["Loader","oldFetch()"],"names":{"title":"oldFetch()","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"oldFetch"},{"kind":"text","spelling":"()"}]},"functionSignature":{"returns":[{"kind":"text","spelling":"()"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"oldFetch"},{"kind":"text","spelling":"()"}],"accessLevel":"public","availability":[{"domain":"iOS","introduced":{"major":15,"minor":0},"deprecated":{"major":17,"minor":0},"renamed":"fetch(url:)"}],"location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":135,"character":16}}},{"kind":{"identifier":"swift.func","displayName":"Function"},"identifier":{"precise":"s:9SwiftDemo16makeDefaultPointAA0E0VyF","interfaceLanguage":"swift"},"pathComponents":["makeDefaultPoint()"],"names":{"title":"makeDefaultPoint()","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"makeDefaultPoint"},{"kind":"text","spelling":"() -> "},{"kind":"typeIdentifier","spelling":"Point","preciseIdentifier":"s:9SwiftDemo5PointV"}]},"functionSignature":{"returns":[{"kind":"typeIdentifier","spelling":"Point","preciseIdentifier":"s:9SwiftDemo5PointV"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"makeDefaultPoint"},{"kind":"text","spelling":"() -> "},{"kind":"typeIdentifier","spelling":"Point","preciseIdentifier":"s:9SwiftDemo5PointV"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":138,"character":12}}},{"kind":{"identifier":"swift.var","displayName":"Global Variable"},"identifier":{"precise":"s:9SwiftDemo13defaultFlavorAA0D0Ovp","interfaceLanguage":"swift"},"pathComponents":["defaultFlavor"],"names":{"title":"defaultFlavor","subHeading":[{"kind":"keyword","spelling":"let"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"defaultFlavor"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Flavor","preciseIdentifier":"s:9SwiftDemo6FlavorO"}]},"declarationFragments":[{"kind":"keyword","spelling":"let"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"defaultFlavor"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Flavor","preciseIdentifier":"s:9SwiftDemo6FlavorO"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":139,"character":11}}},{"kind":{"identifier":"swift.var","displayName":"Global Variable"},"identifier":{"precise":"s:9SwiftDemo13globalCounterSivp","interfaceLanguage":"swift"},"pathComponents":["globalCounter"],"names":{"title":"globalCounter","subHeading":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"globalCounter"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"}]},"declarationFragments":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"globalCounter"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":140,"character":11}}},{"kind":{"identifier":"swift.typealias","displayName":"Type Alias"},"identifier":{"precise":"s:9SwiftDemo11Coordinatesa","interfaceLanguage":"swift"},"pathComponents":["Coordinates"],"names":{"title":"Coordinates","navigator":[{"kind":"identifier","spelling":"Coordinates"}],"subHeading":[{"kind":"keyword","spelling":"typealias"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Coordinates"}]},"declarationFragments":[{"kind":"keyword","spelling":"typealias"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Coordinates"},{"kind":"text","spelling":" = (latitude"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":", longitude"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":")"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Shapes.swift","position":{"line":141,"character":17}}},{"kind":{"identifier":"swift.func","displayName":"Function"},"identifier":{"precise":"s:9SwiftDemo11checkedSideyS2dKF","interfaceLanguage":"swift"},"pathComponents":["checkedSide(_:)"],"names":{"title":"checkedSide(_:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"checkedSide"},{"kind":"text","spelling":"("},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":") "},{"kind":"keyword","spelling":"throws"},{"kind":"text","spelling":" -> "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"}]},"functionSignature":{"parameters":[{"name":"side","declarationFragments":[{"kind":"identifier","spelling":"side"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"}]}],"returns":[{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"checkedSide"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"_"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"side"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"},{"kind":"text","spelling":") "},{"kind":"keyword","spelling":"throws"},{"kind":"text","spelling":" -> "},{"kind":"typeIdentifier","spelling":"Double","preciseIdentifier":"s:Sd"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Values.swift","position":{"line":3,"character":12}}},{"kind":{"identifier":"swift.func","displayName":"Function"},"identifier":{"precise":"s:9SwiftDemo8echoInt8ys0D0VADF","interfaceLanguage":"swift"},"pathComponents":["echoInt8(_:)"],"names":{"title":"echoInt8(_:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"echoInt8"},{"kind":"text","spelling":"("},{"kind":"typeIdentifier","spelling":"Int8","preciseIdentifier":"s:s4Int8V"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"Int8","preciseIdentifier":"s:s4Int8V"}]},"functionSignature":{"parameters":[{"name":"value","declarationFragments":[{"kind":"identifier","spelling":"value"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int8","preciseIdentifier":"s:s4Int8V"}]}],"returns":[{"kind":"typeIdentifier","spelling":"Int8","preciseIdentifier":"s:s4Int8V"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"echoInt8"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"_"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"value"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int8","preciseIdentifier":"s:s4Int8V"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"Int8","preciseIdentifier":"s:s4Int8V"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Values.swift","position":{"line":8,"character":12}}},{"kind":{"identifier":"swift.func","displayName":"Function"},"identifier":{"precise":"s:9SwiftDemo10echoUInt64ys0D0VADF","interfaceLanguage":"swift"},"pathComponents":["echoUInt64(_:)"],"names":{"title":"echoUInt64(_:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"echoUInt64"},{"kind":"text","spelling":"("},{"kind":"typeIdentifier","spelling":"UInt64","preciseIdentifier":"s:s6UInt64V"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"UInt64","preciseIdentifier":"s:s6UInt64V"}]},"functionSignature":{"parameters":[{"name":"value","declarationFragments":[{"kind":"identifier","spelling":"value"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"UInt64","preciseIdentifier":"s:s6UInt64V"}]}],"returns":[{"kind":"typeIdentifier","spelling":"UInt64","preciseIdentifier":"s:s6UInt64V"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"echoUInt64"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"_"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"value"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"UInt64","preciseIdentifier":"s:s6UInt64V"},{"kind":"text","spelling":") -> "},{"kind":"typeIdentifier","spelling":"UInt64","preciseIdentifier":"s:s6UInt64V"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Values.swift","position":{"line":9,"character":12}}},{"kind":{"identifier":"swift.func","displayName":"Function"},"identifier":{"precise":"s:9SwiftDemo10largestIntSiyF","interfaceLanguage":"swift"},"pathComponents":["largestInt()"],"names":{"title":"largestInt()","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"largestInt"},{"kind":"text","spelling":"() -> "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"}]},"functionSignature":{"returns":[{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"largestInt"},{"kind":"text","spelling":"() -> "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Values.swift","position":{"line":10,"character":12}}},{"kind":{"identifier":"swift.func","displayName":"Function"},"identifier":{"precise":"s:9SwiftDemo5shoutySSSgACF","interfaceLanguage":"swift"},"pathComponents":["shout(_:)"],"names":{"title":"shout(_:)","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"shout"},{"kind":"text","spelling":"("},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":"?) -> "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":"?"}]},"functionSignature":{"parameters":[{"name":"name","declarationFragments":[{"kind":"identifier","spelling":"name"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":"?"}]}],"returns":[{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":"?"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"shout"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"_"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"name"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":"?) -> "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":"?"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Values.swift","position":{"line":11,"character":12}}},{"kind":{"identifier":"swift.class","displayName":"Class"},"identifier":{"precise":"s:9SwiftDemo7TrackerC","interfaceLanguage":"swift"},"pathComponents":["Tracker"],"names":{"title":"Tracker","navigator":[{"kind":"identifier","spelling":"Tracker"}],"subHeading":[{"kind":"keyword","spelling":"class"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Tracker"}]},"declarationFragments":[{"kind":"keyword","spelling":"final"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"class"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Tracker"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Values.swift","position":{"line":13,"character":19}}},{"kind":{"identifier":"swift.type.property","displayName":"Type Property"},"identifier":{"precise":"s:9SwiftDemo7TrackerC9liveCountSivpZ","interfaceLanguage":"swift"},"pathComponents":["Tracker","liveCount"],"names":{"title":"liveCount","subHeading":[{"kind":"keyword","spelling":"static"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"liveCount"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"}]},"declarationFragments":[{"kind":"keyword","spelling":"static"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"liveCount"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":" { get }"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Values.swift","position":{"line":14,"character":35}}},{"kind":{"identifier":"swift.property","displayName":"Instance Property"},"identifier":{"precise":"s:9SwiftDemo7TrackerC2idSivp","interfaceLanguage":"swift"},"pathComponents":["Tracker","id"],"names":{"title":"id","subHeading":[{"kind":"keyword","spelling":"let"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"id"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"}]},"declarationFragments":[{"kind":"keyword","spelling":"let"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"id"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Values.swift","position":{"line":15,"character":15}}},{"kind":{"identifier":"swift.init","displayName":"Initializer"},"identifier":{"precise":"s:9SwiftDemo7TrackerC2idACSi_tcfc","interfaceLanguage":"swift"},"pathComponents":["Tracker","init(id:)"],"names":{"title":"init(id:)","subHeading":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"id"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":")"}]},"functionSignature":{"parameters":[{"name":"id","declarationFragments":[{"kind":"identifier","spelling":"id"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"}]}]},"declarationFragments":[{"kind":"keyword","spelling":"init"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"id"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int","preciseIdentifier":"s:Si"},{"kind":"text","spelling":")"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Values.swift","position":{"line":17,"character":11}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:9SwiftDemo7TrackerC4sameACyF","interfaceLanguage":"swift"},"pathComponents":["Tracker","same()"],"names":{"title":"same()","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"same"},{"kind":"text","spelling":"() -> "},{"kind":"typeIdentifier","spelling":"Tracker","preciseIdentifier":"s:9SwiftDemo7TrackerC"}]},"functionSignature":{"returns":[{"kind":"typeIdentifier","spelling":"Tracker","preciseIdentifier":"s:9SwiftDemo7TrackerC"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"same"},{"kind":"text","spelling":"() -> "},{"kind":"typeIdentifier","spelling":"Tracker","preciseIdentifier":"s:9SwiftDemo7TrackerC"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Values.swift","position":{"line":24,"character":16}}}],"relationships":[{"kind":"requirementOf","source":"s:9SwiftDemo7GreeterP5greet4nameS2S_tF","target":"s:9SwiftDemo7GreeterP"},{"kind":"conformsTo","source":"s:9SwiftDemo0B0C","target":"s:9SwiftDemo7GreeterP"},{"kind":"memberOf","source":"s:9SwiftDemo0B0CACycfc","target":"s:9SwiftDemo0B0C"},{"kind":"memberOf","source":"s:9SwiftDemo0B0C5greet4nameS2S_tF","target":"s:9SwiftDemo0B0C","sourceOrigin":{"identifier":"s:9SwiftDemo7GreeterP5greet4nameS2S_tF","displayName":"Greeter.greet(name:)"}},{"kind":"conformsTo","source":"s:9SwiftDemo5PointV","target":"s:s23CustomStringConvertibleP","targetFallback":"Swift.CustomStringConvertible"},{"kind":"memberOf","source":"s:9SwiftDemo5PointV1xSdvp","target":"s:9SwiftDemo5PointV"},{"kind":"memberOf","source":"s:9SwiftDemo5PointV1ySdvp","target":"s:9SwiftDemo5PointV"},{"kind":"memberOf","source":"s:9SwiftDemo5PointV1x1yACSd_Sdtcfc","target":"s:9SwiftDemo5PointV"},{"kind":"memberOf","source":"s:SYsSHRzSH8RawValueSYRpzrlE04hashB0Sivp::SYNTHESIZED::s:9SwiftDemo6FlavorO","target":"s:9SwiftDemo6FlavorO","sourceOrigin":{"identifier":"s:SYsSHRzSH8RawValueSYRpzrlE04hashB0Sivp","displayName":"RawRepresentable.hashValue"}},{"kind":"memberOf","source":"s:SYsSHRzSH8RawValueSYRpzrlE4hash4intoys6HasherVz_tF::SYNTHESIZED::s:9SwiftDemo6FlavorO","target":"s:9SwiftDemo6FlavorO","sourceOrigin":{"identifier":"s:SYsSHRzSH8RawValueSYRpzrlE4hash4intoys6HasherVz_tF","displayName":"RawRepresentable.hash(into:)"}},{"kind":"memberOf","source":"s:SQsRi_zRi0_zrlE2neoiySbx_xtFZ::SYNTHESIZED::s:9SwiftDemo6FlavorO","target":"s:9SwiftDemo6FlavorO","sourceOrigin":{"identifier":"s:SQsRi_zRi0_zrlE2neoiySbx_xtFZ","displayName":"Equatable.!=(_:_:)"}},{"kind":"conformsTo","source":"s:9SwiftDemo6FlavorO","target":"s:SQ","targetFallback":"Swift.Equatable"},{"kind":"conformsTo","source":"s:9SwiftDemo6FlavorO","target":"s:SH","targetFallback":"Swift.Hashable"},{"kind":"conformsTo","source":"s:9SwiftDemo6FlavorO","target":"s:SY","targetFallback":"Swift.RawRepresentable"},{"kind":"conformsTo","source":"s:9SwiftDemo6FlavorO","target":"s:s23CustomStringConvertibleP","targetFallback":"Swift.CustomStringConvertible"},{"kind":"memberOf","source":"s:9SwiftDemo6FlavorO7vanillayA2CmF","target":"s:9SwiftDemo6FlavorO"},{"kind":"memberOf","source":"s:9SwiftDemo6FlavorO9chocolateyA2CmF","target":"s:9SwiftDemo6FlavorO"},{"kind":"memberOf","source":"s:9SwiftDemo6FlavorO8rawValueACSgSi_tcfc","target":"s:9SwiftDemo6FlavorO","sourceOrigin":{"identifier":"s:SY8rawValuexSg03RawB0Qz_tcfc","displayName":"RawRepresentable.init(rawValue:)"}},{"kind":"memberOf","source":"s:9SwiftDemo0B0C5greet4name5timesS2S_SitF","target":"s:9SwiftDemo0B0C"},{"kind":"memberOf","source":"s:9SwiftDemo0B0C7versionSSvpZ","target":"s:9SwiftDemo0B0C"},{"kind":"conformsTo","source":"s:9SwiftDemo5PointV","target":"s:s9EscapableP","targetFallback":"Swift.Escapable"},{"kind":"conformsTo","source":"s:9SwiftDemo5PointV","target":"s:s8CopyableP","targetFallback":"Swift.Copyable"},{"kind":"memberOf","source":"s:9SwiftDemo5PointV11descriptionSSvp","target":"s:9SwiftDemo5PointV","sourceOrigin":{"identifier":"s:s23CustomStringConvertibleP11descriptionSSvp","displayName":"CustomStringConvertible.description"}},{"kind":"memberOf","source":"s:9SwiftDemo5PointV6lengthSdvp","target":"s:9SwiftDemo5PointV"},{"kind":"conformsTo","source":"s:9SwiftDemo6FlavorO","target":"s:s9EscapableP","targetFallback":"Swift.Escapable"},{"kind":"conformsTo","source":"s:9SwiftDemo6FlavorO","target":"s:s8CopyableP","targetFallback":"Swift.Copyable"},{"kind":"memberOf","source":"s:9SwiftDemo6FlavorO11descriptionSSvp","target":"s:9SwiftDemo6FlavorO","sourceOrigin":{"identifier":"s:s23CustomStringConvertibleP11descriptionSSvp","displayName":"CustomStringConvertible.description"}},{"kind":"conformsTo","source":"s:9SwiftDemo5ShapeP","target":"s:9SwiftDemo7GreeterP"},{"kind":"requirementOf","source":"s:9SwiftDemo5ShapeP4areaSdvp","target":"s:9SwiftDemo5ShapeP"},{"kind":"requirementOf","source":"s:9SwiftDemo5ShapeP5sidesSivpZ","target":"s:9SwiftDemo5ShapeP"},{"kind":"memberOf","source":"s:9SwiftDemo7PolygonC4nameSSvp","target":"s:9SwiftDemo7PolygonC"},{"kind":"memberOf","source":"s:9SwiftDemo7PolygonC11vertexCountSivp","target":"s:9SwiftDemo7PolygonC"},{"kind":"memberOf","source":"s:9SwiftDemo7PolygonC6sharedACvpZ","target":"s:9SwiftDemo7PolygonC"},{"kind":"memberOf","source":"s:9SwiftDemo7PolygonC4name11vertexCountACSS_Sitcfc","target":"s:9SwiftDemo7PolygonC"},{"kind":"memberOf","source":"s:9SwiftDemo7PolygonC4nameACSgSS_tcfc","target":"s:9SwiftDemo7PolygonC"},{"kind":"memberOf","source":"s:9SwiftDemo7PolygonC5scale2byySd_tF","target":"s:9SwiftDemo7PolygonC"},{"kind":"memberOf","source":"s:9SwiftDemo7PolygonC5scale2byySi_tF","target":"s:9SwiftDemo7PolygonC"},{"kind":"memberOf","source":"s:9SwiftDemo7PolygonC5scale1x1yySd_SdtF","target":"s:9SwiftDemo7PolygonC"},{"kind":"memberOf","source":"s:9SwiftDemo7PolygonC4makeACyFZ","target":"s:9SwiftDemo7PolygonC"},{"kind":"memberOf","source":"s:9SwiftDemo7PolygonC8describeySSACSgFZ","target":"s:9SwiftDemo7PolygonC"},{"kind":"memberOf","source":"s:9SwiftDemo7PolygonCyAA5PointVSicip","target":"s:9SwiftDemo7PolygonC"},{"kind":"conformsTo","source":"s:9SwiftDemo6SquareC","target":"s:9SwiftDemo5ShapeP"},{"kind":"conformsTo","source":"s:9SwiftDemo6SquareC","target":"s:9SwiftDemo7GreeterP"},{"kind":"inheritsFrom","source":"s:9SwiftDemo6SquareC","target":"s:9SwiftDemo7PolygonC"},{"kind":"memberOf","source":"s:9SwiftDemo6SquareC4sideSdvp","target":"s:9SwiftDemo6SquareC"},{"kind":"memberOf","source":"s:9SwiftDemo6SquareC4sideACSd_tcfc","target":"s:9SwiftDemo6SquareC"},{"kind":"memberOf","source":"s:9SwiftDemo6SquareC4areaSdvp","target":"s:9SwiftDemo6SquareC","sourceOrigin":{"identifier":"s:9SwiftDemo5ShapeP4areaSdvp","displayName":"Shape.area"}},{"kind":"memberOf","source":"s:9SwiftDemo6SquareC5sidesSivpZ","target":"s:9SwiftDemo6SquareC","sourceOrigin":{"identifier":"s:9SwiftDemo5ShapeP5sidesSivpZ","displayName":"Shape.sides"}},{"kind":"memberOf","source":"s:9SwiftDemo6SquareC5greet4nameS2S_tF","target":"s:9SwiftDemo6SquareC","sourceOrigin":{"identifier":"s:9SwiftDemo7GreeterP5greet4nameS2S_tF","displayName":"Greeter.greet(name:)"}},{"kind":"memberOf","source":"s:9SwiftDemo6SquareC5scale2byySd_tF","target":"s:9SwiftDemo6SquareC"},{"kind":"overrides","source":"s:9SwiftDemo6SquareC5scale2byySd_tF","target":"s:9SwiftDemo7PolygonC5scale2byySd_tF"},{"kind":"memberOf","source":"s:SYsSHRzSH8RawValueSYRpzrlE04hashB0Sivp::SYNTHESIZED::s:9SwiftDemo13PrecipitationO","target":"s:9SwiftDemo13PrecipitationO","sourceOrigin":{"identifier":"s:SYsSHRzSH8RawValueSYRpzrlE04hashB0Sivp","displayName":"RawRepresentable.hashValue"}},{"kind":"memberOf","source":"s:SYsSHRzSH8RawValueSYRpzrlE4hash4intoys6HasherVz_tF::SYNTHESIZED::s:9SwiftDemo13PrecipitationO","target":"s:9SwiftDemo13PrecipitationO","sourceOrigin":{"identifier":"s:SYsSHRzSH8RawValueSYRpzrlE4hash4intoys6HasherVz_tF","displayName":"RawRepresentable.hash(into:)"}},{"kind":"memberOf","source":"s:SQsRi_zRi0_zrlE2neoiySbx_xtFZ::SYNTHESIZED::s:9SwiftDemo13PrecipitationO","target":"s:9SwiftDemo13PrecipitationO","sourceOrigin":{"identifier":"s:SQsRi_zRi0_zrlE2neoiySbx_xtFZ","displayName":"Equatable.!=(_:_:)"}},{"kind":"conformsTo","source":"s:9SwiftDemo13PrecipitationO","target":"s:SQ","targetFallback":"Swift.Equatable"},{"kind":"conformsTo","source":"s:9SwiftDemo13PrecipitationO","target":"s:SH","targetFallback":"Swift.Hashable"},{"kind":"conformsTo","source":"s:9SwiftDemo13PrecipitationO","target":"s:SY","targetFallback":"Swift.RawRepresentable"},{"kind":"memberOf","source":"s:9SwiftDemo13PrecipitationO4rainyA2CmF","target":"s:9SwiftDemo13PrecipitationO"},{"kind":"memberOf","source":"s:9SwiftDemo13PrecipitationO4snowyA2CmF","target":"s:9SwiftDemo13PrecipitationO"},{"kind":"memberOf","source":"s:9SwiftDemo13PrecipitationO4noneyA2CmF","target":"s:9SwiftDemo13PrecipitationO"},{"kind":"memberOf","source":"s:9SwiftDemo13PrecipitationO8rawValueACSgSS_tcfc","target":"s:9SwiftDemo13PrecipitationO","sourceOrigin":{"identifier":"s:SY8rawValuexSg03RawB0Qz_tcfc","displayName":"RawRepresentable.init(rawValue:)"}},{"kind":"memberOf","source":"s:s5ErrorP10FoundationE20localizedDescriptionSSvp::SYNTHESIZED::s:9SwiftDemo10ShapeErrorO","target":"s:9SwiftDemo10ShapeErrorO","sourceOrigin":{"identifier":"s:s5ErrorP10FoundationE20localizedDescriptionSSvp","displayName":"Error.localizedDescription"}},{"kind":"conformsTo","source":"s:9SwiftDemo10ShapeErrorO","target":"s:s5ErrorP","targetFallback":"Swift.Error"},{"kind":"conformsTo","source":"s:9SwiftDemo10ShapeErrorO","target":"s:s8SendableP","targetFallback":"Swift.Sendable"},{"kind":"conformsTo","source":"s:9SwiftDemo10ShapeErrorO","target":"s:s16SendableMetatypeP","targetFallback":"Swift.SendableMetatype"},{"kind":"memberOf","source":"s:9SwiftDemo10ShapeErrorO11invalidSideyACSdcACmF","target":"s:9SwiftDemo10ShapeErrorO"},{"kind":"memberOf","source":"s:9SwiftDemo10ShapeErrorO12tooManySidesyACSi_SitcACmF","target":"s:9SwiftDemo10ShapeErrorO"},{"kind":"memberOf","source":"s:9SwiftDemo10ShapeErrorO7unknownyA2CmF","target":"s:9SwiftDemo10ShapeErrorO"},{"kind":"memberOf","source":"s:9SwiftDemo11MeasurementO6lengthyACSdcACmF","target":"s:9SwiftDemo11MeasurementO"},{"kind":"memberOf","source":"s:9SwiftDemo11MeasurementO4areayACSd_SdtcACmF","target":"s:9SwiftDemo11MeasurementO"},{"kind":"memberOf","source":"s:9SwiftDemo11MeasurementO4noneyA2CmF","target":"s:9SwiftDemo11MeasurementO"},{"kind":"memberOf","source":"s:9SwiftDemo11MeasurementO4UnitV","target":"s:9SwiftDemo11MeasurementO"},{"kind":"memberOf","source":"s:9SwiftDemo11MeasurementO4UnitV6symbolSSvp","target":"s:9SwiftDemo11MeasurementO4UnitV"},{"kind":"memberOf","source":"s:9SwiftDemo11MeasurementO4UnitV6symbolAESS_tcfc","target":"s:9SwiftDemo11MeasurementO4UnitV"},{"kind":"memberOf","source":"s:9SwiftDemo11MeasurementO6isNoneSbvp","target":"s:9SwiftDemo11MeasurementO"},{"kind":"memberOf","source":"s:9SwiftDemo4RingV5innerAA5PointVvp","target":"s:9SwiftDemo4RingV"},{"kind":"memberOf","source":"s:9SwiftDemo4RingV5outerAA5PointVvp","target":"s:9SwiftDemo4RingV"},{"kind":"memberOf","source":"s:9SwiftDemo4RingV5inner5outerAcA5PointV_AGtcfc","target":"s:9SwiftDemo4RingV"},{"kind":"memberOf","source":"s:9SwiftDemo4RingV6expand2byySd_tF","target":"s:9SwiftDemo4RingV"},{"kind":"memberOf","source":"s:9SwiftDemo4RingV1poiyA2C_ACtFZ","target":"s:9SwiftDemo4RingV"},{"kind":"memberOf","source":"s:ScA12_ConcurrencyE18withSerialExecutoryqd__qd__Scf_pqd_0_YKXEqd_0_YKs5ErrorRd_0_Ri_d__r0_lF::SYNTHESIZED::s:9SwiftDemo7CounterC","target":"s:9SwiftDemo7CounterC","sourceOrigin":{"identifier":"s:ScA12_ConcurrencyE18withSerialExecutoryqd__qd__Scf_pqd_0_YKXEqd_0_YKs5ErrorRd_0_Ri_d__r0_lF","displayName":"Actor.withSerialExecutor(_:)"}},{"kind":"memberOf","source":"s:ScA12_ConcurrencyE18withSerialExecutoryqd__qd__Scf_pYaqd_0_YKYCXEYaqd_0_YKs5ErrorRd_0_Ri_d__r0_lF::SYNTHESIZED::s:9SwiftDemo7CounterC","target":"s:9SwiftDemo7CounterC","sourceOrigin":{"identifier":"s:ScA12_ConcurrencyE18withSerialExecutoryqd__qd__Scf_pYaqd_0_YKYCXEYaqd_0_YKs5ErrorRd_0_Ri_d__r0_lF","displayName":"Actor.withSerialExecutor(_:)"}},{"kind":"memberOf","source":"s:ScA12_ConcurrencyE20preconditionIsolated_4file4lineySSyXK_s12StaticStringVSutF::SYNTHESIZED::s:9SwiftDemo7CounterC","target":"s:9SwiftDemo7CounterC","sourceOrigin":{"identifier":"s:ScA12_ConcurrencyE20preconditionIsolated_4file4lineySSyXK_s12StaticStringVSutF","displayName":"Actor.preconditionIsolated(_:file:line:)"}},{"kind":"memberOf","source":"s:ScA12_ConcurrencyE14assertIsolated_4file4lineySSyXK_s12StaticStringVSutF::SYNTHESIZED::s:9SwiftDemo7CounterC","target":"s:9SwiftDemo7CounterC","sourceOrigin":{"identifier":"s:ScA12_ConcurrencyE14assertIsolated_4file4lineySSyXK_s12StaticStringVSutF","displayName":"Actor.assertIsolated(_:file:line:)"}},{"kind":"memberOf","source":"s:ScA12_ConcurrencyE14assumeIsolated_4file4lineqd__qd__xYiKXE_s12StaticStringVSutKs8SendableRd__lF::SYNTHESIZED::s:9SwiftDemo7CounterC","target":"s:9SwiftDemo7CounterC","sourceOrigin":{"identifier":"s:ScA12_ConcurrencyE14assumeIsolated_4file4lineqd__qd__xYiKXE_s12StaticStringVSutKs8SendableRd__lF","displayName":"Actor.assumeIsolated(_:file:line:)"}},{"kind":"conformsTo","source":"s:9SwiftDemo7CounterC","target":"s:ScA","targetFallback":"_Concurrency.Actor"},{"kind":"conformsTo","source":"s:9SwiftDemo7CounterC","target":"s:s8SendableP","targetFallback":"Swift.Sendable"},{"kind":"conformsTo","source":"s:9SwiftDemo7CounterC","target":"s:s16SendableMetatypeP","targetFallback":"Swift.SendableMetatype"},{"kind":"memberOf","source":"s:9SwiftDemo7CounterC5valueSivp","target":"s:9SwiftDemo7CounterC"},{"kind":"memberOf","source":"s:9SwiftDemo7CounterCACycfc","target":"s:9SwiftDemo7CounterC"},{"kind":"memberOf","source":"s:9SwiftDemo7CounterC9incrementSiyF","target":"s:9SwiftDemo7CounterC"},{"kind":"memberOf","source":"s:9SwiftDemo7CounterC5labelSSyF","target":"s:9SwiftDemo7CounterC"},{"kind":"conformsTo","source":"s:9SwiftDemo6CanvasC","target":"s:s8SendableP","targetFallback":"Swift.Sendable"},{"kind":"memberOf","source":"s:9SwiftDemo6CanvasCACycfc","target":"s:9SwiftDemo6CanvasC"},{"kind":"memberOf","source":"s:9SwiftDemo6CanvasC4drawyyAA5Shape_pF","target":"s:9SwiftDemo6CanvasC"},{"kind":"memberOf","source":"s:9SwiftDemo6LoaderCACycfc","target":"s:9SwiftDemo6LoaderC"},{"kind":"memberOf","source":"s:9SwiftDemo6LoaderC4load4path10Foundation4DataVSS_tKF","target":"s:9SwiftDemo6LoaderC"},{"kind":"memberOf","source":"s:9SwiftDemo6LoaderC5fetch3urlSS10Foundation3URLV_tYaKF","target":"s:9SwiftDemo6LoaderC"},{"kind":"memberOf","source":"s:9SwiftDemo6LoaderC4wait7secondsySd_tYaF","target":"s:9SwiftDemo6LoaderC"},{"kind":"memberOf","source":"s:9SwiftDemo6LoaderC9transformyxxAA5ShapeRzlF","target":"s:9SwiftDemo6LoaderC"},{"kind":"memberOf","source":"s:9SwiftDemo6LoaderC5first2ofxSgSayxG_tlF","target":"s:9SwiftDemo6LoaderC"},{"kind":"memberOf","source":"s:9SwiftDemo6LoaderC14withCompletionyyys6ResultOySSAA10ShapeErrorOGcF","target":"s:9SwiftDemo6LoaderC"},{"kind":"memberOf","source":"s:9SwiftDemo6LoaderC4eachyyySiXEF","target":"s:9SwiftDemo6LoaderC"},{"kind":"memberOf","source":"s:9SwiftDemo6LoaderC6lookup5table3keySiSgSDySSSiG_SStF","target":"s:9SwiftDemo6LoaderC"},{"kind":"memberOf","source":"s:9SwiftDemo6LoaderC6updateyyAA5PointVzF","target":"s:9SwiftDemo6LoaderC"},{"kind":"memberOf","source":"s:9SwiftDemo6LoaderC10modernOnlyyyF","target":"s:9SwiftDemo6LoaderC"},{"kind":"memberOf","source":"s:9SwiftDemo6LoaderC11legacyFetchyyF","target":"s:9SwiftDemo6LoaderC"},{"kind":"memberOf","source":"s:9SwiftDemo6LoaderC8oldFetchyyF","target":"s:9SwiftDemo6LoaderC"},{"kind":"memberOf","source":"s:9SwiftDemo7TrackerC9liveCountSivpZ","target":"s:9SwiftDemo7TrackerC"},{"kind":"memberOf","source":"s:9SwiftDemo7TrackerC2idSivp","target":"s:9SwiftDemo7TrackerC"},{"kind":"memberOf","source":"s:9SwiftDemo7TrackerC2idACSi_tcfc","target":"s:9SwiftDemo7TrackerC"},{"kind":"memberOf","source":"s:9SwiftDemo7TrackerC4sameACyF","target":"s:9SwiftDemo7TrackerC"}]} \ No newline at end of file diff --git a/metadata-generator/TestFixtures/SwiftDemo/symbolgraphs/SwiftDemo@Swift.symbols.json b/metadata-generator/TestFixtures/SwiftDemo/symbolgraphs/SwiftDemo@Swift.symbols.json new file mode 100644 index 000000000..8ef8982db --- /dev/null +++ b/metadata-generator/TestFixtures/SwiftDemo/symbolgraphs/SwiftDemo@Swift.symbols.json @@ -0,0 +1 @@ +{"metadata":{"formatVersion":{"major":0,"minor":6,"patch":0},"generator":"Apple Swift version 6.4 (swiftlang-6.4.0.34.1 clang-2100.3.34.1)"},"module":{"name":"SwiftDemo","platform":{"architecture":"arm64","environment":"simulator","vendor":"apple","operatingSystem":{"name":"ios","minimumVersion":{"major":15,"minor":0}}}},"symbols":[{"kind":{"identifier":"swift.property","displayName":"Instance Property"},"identifier":{"precise":"s:SS9SwiftDemoE7shoutedSSvp","interfaceLanguage":"swift"},"pathComponents":["String","shouted"],"names":{"title":"shouted","subHeading":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"shouted"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"}]},"swiftExtension":{"extendedModule":"Swift","typeKind":"swift.struct"},"declarationFragments":[{"kind":"keyword","spelling":"var"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"shouted"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"String","preciseIdentifier":"s:SS"},{"kind":"text","spelling":" { "},{"kind":"keyword","spelling":"get"},{"kind":"text","spelling":" }"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Extensions.swift","position":{"line":18,"character":15}}},{"kind":{"identifier":"swift.method","displayName":"Instance Method"},"identifier":{"precise":"s:Sa9SwiftDemoAA5PointVRszlE8centroidACyF","interfaceLanguage":"swift"},"pathComponents":["Array","centroid()"],"names":{"title":"centroid()","subHeading":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"centroid"},{"kind":"text","spelling":"() -> "},{"kind":"typeIdentifier","spelling":"Point","preciseIdentifier":"s:9SwiftDemo5PointV"}]},"functionSignature":{"returns":[{"kind":"typeIdentifier","spelling":"Point","preciseIdentifier":"s:9SwiftDemo5PointV"}]},"swiftGenerics":{"parameters":[{"name":"Element","index":0,"depth":0}],"constraints":[{"kind":"sameType","lhs":"Element","rhs":"Point","rhsPrecise":"s:9SwiftDemo5PointV"}]},"swiftExtension":{"extendedModule":"Swift","typeKind":"swift.struct","constraints":[{"kind":"sameType","lhs":"Element","rhs":"Point","rhsPrecise":"s:9SwiftDemo5PointV"}]},"declarationFragments":[{"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"centroid"},{"kind":"text","spelling":"() -> "},{"kind":"typeIdentifier","spelling":"Point","preciseIdentifier":"s:9SwiftDemo5PointV"}],"accessLevel":"public","location":{"uri":"file://Sources/SwiftDemo/Extensions.swift","position":{"line":22,"character":16}}}],"relationships":[{"kind":"memberOf","source":"s:SS9SwiftDemoE7shoutedSSvp","target":"s:SS","targetFallback":"Swift.String"},{"kind":"memberOf","source":"s:Sa9SwiftDemoAA5PointVRszlE8centroidACyF","target":"s:Sa","targetFallback":"Swift.Array"}]} \ No newline at end of file diff --git a/metadata-generator/build-step-metadata-generator.py b/metadata-generator/build-step-metadata-generator.py index 1acd946c9..cb1f0491f 100755 --- a/metadata-generator/build-step-metadata-generator.py +++ b/metadata-generator/build-step-metadata-generator.py @@ -114,6 +114,8 @@ def map_and_list(func, iterable): .format(docset_platform)) yaml_output_folder = env_or_none("NS_DEBUG_METADATA_PATH") or env_or_none("TNS_DEBUG_METADATA_PATH") strict_includes = env_or_none("NS_DEBUG_METADATA_STRICT_INCLUDES") or env_or_none("TNS_DEBUG_METADATA_STRICT_INCLUDES") +swift_symbolgraph_dir = env_or_none("NS_SWIFT_SYMBOLGRAPH_DIR") or env_or_none("TNS_SWIFT_SYMBOLGRAPH_DIR") +skip_objc = env_bool("NS_SKIP_OBJC_METADATA") or env_bool("TNS_SKIP_OBJC_METADATA") def save_stream_to_file(filename, stream): @@ -133,6 +135,12 @@ def generate_metadata(arch): if strict_includes is not None: generator_call.extend(["-strict-includes={}".format(strict_includes)]) + # Swift-only mode or Swift supplement + if swift_symbolgraph_dir is not None and len(swift_symbolgraph_dir) > 0: + generator_call.extend(["--swift-symbolgraph-dir", swift_symbolgraph_dir]) + if skip_objc: + generator_call.extend(["--skip-objc"]) + # optionally add typescript output folder if typescript_output_folder is not None: current_typescript_output_folder = os.path.join(typescript_output_folder, arch) diff --git a/metadata-generator/src/CMakeLists.txt b/metadata-generator/src/CMakeLists.txt index 037abdc98..11f96abb4 100644 --- a/metadata-generator/src/CMakeLists.txt +++ b/metadata-generator/src/CMakeLists.txt @@ -35,6 +35,20 @@ set(GENERATOR_HEADERS Utils/StringUtils.h Yaml/MetaYamlTraits.h Yaml/YamlSerializer.h + + # Swift support + Swift/CapabilityClassifier.h + Swift/CoverageReport.h + Swift/FragmentTokens.h + Swift/ProbeEmitter.h + Swift/ProbeVerifier.h + Swift/SwiftSource.h + Swift/SwiftSurface.h + Swift/SwiftTypes.h + Swift/SwiftIR.h + Swift/SymbolGraphLoader.h + Swift/ThunkEmitter.h + TypeScript/SwiftDefinitionWriter.h ) set(GENERATOR_SOURCES @@ -63,6 +77,20 @@ set(GENERATOR_SOURCES TypeScript/DocSetManager.cpp Utils/fileStream.cpp Utils/memoryStream.cpp + + # Swift support + Swift/CapabilityClassifier.cpp + Swift/CoverageReport.cpp + Swift/FragmentTokens.cpp + Swift/ProbeEmitter.cpp + Swift/ProbeVerifier.cpp + Swift/SwiftSource.cpp + Swift/SwiftSurface.cpp + Swift/SwiftTypes.cpp + Swift/SwiftIR.cpp + Swift/SymbolGraphLoader.cpp + Swift/ThunkEmitter.cpp + TypeScript/SwiftDefinitionWriter.cpp ) include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${LIBXML2_INCLUDE_DIR}) diff --git a/metadata-generator/src/Swift/CapabilityClassifier.cpp b/metadata-generator/src/Swift/CapabilityClassifier.cpp new file mode 100644 index 000000000..4b8846c88 --- /dev/null +++ b/metadata-generator/src/Swift/CapabilityClassifier.cpp @@ -0,0 +1,550 @@ +#include "CapabilityClassifier.h" + +#include +#include + +#include +#include + +namespace Swift { + +const char* toString(Tier tier) { + switch (tier) { + case Tier::ObjCDirect: + return "objc-direct"; + case Tier::SwiftGenerated: + return "swift-generated"; + case Tier::SwiftSpecialized: + return "swift-specialized"; + case Tier::TypeOnly: + return "type-only"; + case Tier::Unsupported: + return "unsupported"; + case Tier::NotApplicable: + return "not-applicable"; + } + return "unsupported"; +} + +const Capability* Classification::find(const std::string& id) const { + auto it = bySymbol.find(id); + return it == bySymbol.end() ? nullptr : &it->second; +} + +bool isCallableKind(SymbolKind kind) { + switch (kind) { + case SymbolKind::EnumCase: + case SymbolKind::Initializer: + case SymbolKind::InstanceMethod: + case SymbolKind::TypeMethod: + case SymbolKind::Operator: + case SymbolKind::InstanceProperty: + case SymbolKind::TypeProperty: + case SymbolKind::InstanceSubscript: + case SymbolKind::TypeSubscript: + case SymbolKind::Function: + case SymbolKind::Variable: + return true; + default: + return false; + } +} + +namespace { + +std::string availabilityDomain(const Platform& platform) { + llvm::StringRef os = platform.operatingSystem; + if (os == "ios") { + return platform.environment == "macabi" ? "macCatalyst" : "iOS"; + } + if (os == "macosx" || os == "macos") { + return "macOS"; + } + if (os == "tvos") { + return "tvOS"; + } + if (os == "watchos") { + return "watchOS"; + } + if (os == "xros" || os == "visionos") { + return "visionOS"; + } + return os.str(); +} + +bool versionAtMost(const Version& a, const Version& b) { + return std::tie(a.major, a.minor, a.patch) <= + std::tie(b.major, b.minor, b.patch); +} + +bool hasAttribute(const Symbol& symbol, llvm::StringRef attribute) { + for (const auto& candidate : symbol.attributes) { + if (llvm::StringRef(candidate).startswith(attribute)) { + return true; + } + } + return false; +} + +bool isPrimitive(const std::string& usr, Bridge& bridge) { + using namespace KnownTypes; + static const char* integers[] = {kInt, kInt8, kInt16, kInt32, kInt64, + kUInt, kUInt8, kUInt16, kUInt32, kUInt64}; + for (const char* candidate : integers) { + if (usr == candidate) { + bridge = Bridge::Integer; + return true; + } + } + if (usr == kDouble || usr == kFloat || usr == kCGFloat) { + bridge = Bridge::Floating; + return true; + } + if (usr == kBool) { + bridge = Bridge::Bool; + return true; + } + if (usr == kString) { + bridge = Bridge::String; + return true; + } + return false; +} + +class Classifier { + public: + Classifier(const Module& module, + const std::map& rejections) + : _module(module), _rejections(rejections) {} + + Classification run() { + // Types first: member classification depends on the owner's tier. + for (const auto& entry : _module.symbols) { + if (isNominalType(entry.second.kind)) { + _result.bySymbol[entry.first] = classifyType(entry.second); + } + } + for (const auto& entry : _module.symbols) { + if (!isNominalType(entry.second.kind)) { + _result.bySymbol[entry.first] = classifyOther(entry.second); + } + } + resolveNames(); + return std::move(_result); + } + + private: + static Capability make(Tier tier, std::string reason = "") { + Capability capability; + capability.tier = tier; + if (!reason.empty()) { + capability.reasons.push_back(std::move(reason)); + } + return capability; + } + + // Reasons shared by every declaration kind. + bool commonRejection(const Symbol& symbol, Capability& out) const { + auto rejected = _rejections.find(symbol.preciseId); + if (rejected != _rejections.end()) { + out = make(Tier::Unsupported, "compiler-rejected:" + rejected->second); + return true; + } + if (llvm::StringRef(symbol.usr).startswith("c:")) { + out = make(Tier::ObjCDirect, "objc-visible"); + return true; + } + if (symbol.access != AccessLevel::Public && + symbol.access != AccessLevel::Open) { + out = make(Tier::Unsupported, "not-public"); + return true; + } + for (const Availability* availability : + applicableAvailability(_module, symbol)) { + if (availability->isUnconditionallyUnavailable) { + out = make(Tier::Unsupported, "unavailable"); + return true; + } + if (availability->obsoleted && _module.platform.minimumVersion && + versionAtMost(*availability->obsoleted, + *_module.platform.minimumVersion)) { + out = make(Tier::Unsupported, "obsoleted"); + return true; + } + } + return false; + } + + Capability classifyType(const Symbol& symbol) const { + Capability capability; + if (commonRejection(symbol, capability)) { + return capability; + } + if (symbol.kind == SymbolKind::Protocol) { + return make(Tier::TypeOnly, "protocol"); + } + if (!symbol.genericParameters.empty()) { + return make(Tier::SwiftSpecialized, "generic"); + } + if (!symbol.parentId.empty()) { + return make(Tier::Unsupported, "nested-type"); + } + // Graphs show suppressed conformances only when the declaration spells + // them; other noncopyable types are caught by compiler verification. + if (llvm::StringRef(symbol.declarationText).contains("~Copyable")) { + return make(Tier::Unsupported, "noncopyable"); + } + if (llvm::StringRef(symbol.declarationText).contains("~Escapable")) { + return make(Tier::Unsupported, "nonescapable"); + } + if (symbol.kind == SymbolKind::Enum) { + for (const auto& id : symbol.memberIds) { + const Symbol* member = _module.find(id); + if (member && member->kind == SymbolKind::EnumCase && + !member->parameters.empty()) { + return make(Tier::Unsupported, "enum-associated-values"); + } + } + } + return make(Tier::SwiftGenerated); + } + + Capability classifyOther(const Symbol& symbol) const { + Capability capability; + switch (symbol.kind) { + case SymbolKind::Deinitializer: + return make(Tier::NotApplicable, "deinitializer"); + case SymbolKind::Macro: + return make(Tier::NotApplicable, "macro"); + case SymbolKind::Extension: + return make(Tier::NotApplicable, "extension-block"); + case SymbolKind::Unknown: + return make(Tier::Unsupported, "unknown-kind"); + default: + break; + } + if (commonRejection(symbol, capability)) { + return capability; + } + if (symbol.kind == SymbolKind::TypeAlias) { + return make(Tier::TypeOnly, "type-alias"); + } + if (symbol.kind == SymbolKind::AssociatedType) { + return make(Tier::TypeOnly, "associated-type"); + } + + const Symbol* owner = + symbol.parentId.empty() ? nullptr : _module.find(symbol.parentId); + bool isMemberKind = symbol.kind != SymbolKind::Function && + symbol.kind != SymbolKind::Variable; + if (symbol.parentId.empty() && isMemberKind) { + // A member whose owner the graph omits (no memberOf edge). + return make(Tier::Unsupported, "missing-owner"); + } + if (!symbol.parentId.empty()) { + if (!owner) { + return make(Tier::Unsupported, "external-type-extension"); + } + if (owner->kind == SymbolKind::Protocol) { + return make(Tier::TypeOnly, "protocol-requirement"); + } + const Capability* ownerCapability = _result.find(owner->preciseId); + if (!ownerCapability || ownerCapability->tier != Tier::SwiftGenerated) { + Tier tier = + ownerCapability && ownerCapability->tier == Tier::SwiftSpecialized + ? Tier::SwiftSpecialized + : Tier::Unsupported; + return make(tier, "owner-not-bridged"); + } + } + + if (symbol.kind == SymbolKind::Operator) { + return make(Tier::Unsupported, "operator"); + } + if (symbol.kind == SymbolKind::InstanceSubscript || + symbol.kind == SymbolKind::TypeSubscript) { + return make(Tier::Unsupported, "subscript"); + } + if (symbol.kind == SymbolKind::EnumCase) { + // Only payload-less enums are bridged (see classifyType). + capability = make(Tier::SwiftGenerated); + capability.jsName = symbol.baseName; + return capability; + } + + if (!symbol.genericParameters.empty()) { + return make(Tier::SwiftSpecialized, "generic"); + } + + bool nonisolated = hasAttribute(symbol, "nonisolated"); + if (!nonisolated && (hasAttribute(symbol, "@MainActor") || + (owner && hasAttribute(*owner, "@MainActor")))) { + return make(Tier::Unsupported, "main-actor"); + } + if (owner && owner->kind == SymbolKind::Actor && !nonisolated && + !symbol.isStatic && symbol.kind != SymbolKind::Initializer) { + return make(Tier::Unsupported, "actor-isolated"); + } + if (symbol.isAsync) { + return make(Tier::Unsupported, "async"); + } + + std::set generics = genericNamesInScope(_module, symbol); + std::vector reasons; + for (const auto& parameter : symbol.parameters) { + if (parameter.modifier == "inout") { + reasons.push_back("inout-parameter"); + continue; + } + if (parameter.isVariadic) { + reasons.push_back("variadic-parameter"); + continue; + } + if (std::find(parameter.attributes.begin(), parameter.attributes.end(), + "@autoclosure") != parameter.attributes.end()) { + reasons.push_back("closure"); + continue; + } + BridgedType bridged = bridge(parameter.type, generics, reasons); + capability.parameters.push_back(std::move(bridged)); + } + + if (symbol.kind == SymbolKind::Initializer) { + // Initializers produce the owner; failable ones may produce nil. + BridgedType self = bridgeOwner(*owner); + self.optional = symbol.isFailable; + capability.result = std::move(self); + } else if (symbol.valueType) { + capability.result = bridge(*symbol.valueType, generics, reasons); + } else if (symbol.returnType) { + capability.result = bridge(*symbol.returnType, generics, reasons); + } else { + capability.result.bridge = Bridge::Void; + } + + std::sort(reasons.begin(), reasons.end()); + reasons.erase(std::unique(reasons.begin(), reasons.end()), reasons.end()); + if (!reasons.empty()) { + bool onlyGeneric = + std::all_of(reasons.begin(), reasons.end(), + [](const std::string& r) { return r == "generic"; }); + return Capability{ + onlyGeneric ? Tier::SwiftSpecialized : Tier::Unsupported, + reasons, + "", + false, + {}, + {}}; + } + + capability.tier = Tier::SwiftGenerated; + capability.jsName = symbol.kind == SymbolKind::Initializer + ? "constructor" + : symbol.baseName; + return capability; + } + + BridgedType bridgeOwner(const Symbol& owner) const { + BridgedType bridged; + bridged.symbolId = owner.preciseId; + bridged.bridge = owner.kind == SymbolKind::Struct ? Bridge::StructBox + : owner.kind == SymbolKind::Enum ? Bridge::EnumCase + : Bridge::ClassHandle; + TypeNode::Component component; + component.name = owner.name; + component.usr = owner.preciseId; + bridged.node.kind = TypeNode::Kind::Nominal; + bridged.node.components.push_back(std::move(component)); + return bridged; + } + + BridgedType bridge(const TypeRef& type, const std::set& generics, + std::vector& reasons) const { + bool complete = true; + BridgedType bridged; + bridged.node = parseType(type, generics, &complete); + if (!complete) { + reasons.push_back("unparsed-type"); + return bridged; + } + const TypeNode* node = &bridged.node; + if (node->kind == TypeNode::Kind::Optional || + node->kind == TypeNode::Kind::ImplicitlyUnwrappedOptional) { + bridged.optional = true; + node = &node->children[0]; + if (node->kind == TypeNode::Kind::Optional || + node->kind == TypeNode::Kind::ImplicitlyUnwrappedOptional) { + reasons.push_back("nested-optional"); + return bridged; + } + } + std::string reason = bridgeNonOptional(*node, bridged); + if (!reason.empty()) { + reasons.push_back(reason); + } + return bridged; + } + + // Returns the rejection reason, or "" with `bridged` filled in. + std::string bridgeNonOptional(const TypeNode& node, + BridgedType& bridged) const { + switch (node.kind) { + case TypeNode::Kind::Void: + bridged.bridge = Bridge::Void; + return ""; + case TypeNode::Kind::GenericParameter: + return "generic"; + case TypeNode::Kind::Function: + return "closure"; + case TypeNode::Kind::Tuple: + return "tuple"; + case TypeNode::Kind::Array: + case TypeNode::Kind::Dictionary: + return "collection"; + case TypeNode::Kind::Existential: + case TypeNode::Kind::Composition: + return "existential"; + case TypeNode::Kind::Opaque: + return "opaque-type"; + case TypeNode::Kind::Metatype: + return "metatype"; + case TypeNode::Kind::Unknown: + return "unparsed-type"; + case TypeNode::Kind::Optional: + case TypeNode::Kind::ImplicitlyUnwrappedOptional: + return "nested-optional"; + case TypeNode::Kind::Nominal: + break; + } + + const std::string& usr = node.usr(); + if (node.components.size() == 1 && node.components[0].arguments.empty() && + isPrimitive(usr, bridged.bridge)) { + return ""; + } + const Symbol* target = usr.empty() ? nullptr : _module.find(usr); + if (target) { + const Capability* capability = _result.find(target->preciseId); + if (capability && capability->tier == Tier::SwiftGenerated && + target->kind != SymbolKind::Protocol) { + bridged = BridgedType{bridgeOwner(*target).bridge, bridged.optional, + target->preciseId, bridged.node}; + return ""; + } + return "unbridged-type:" + llvm::join(target->pathComponents, "."); + } + auto name = _module.externalNames.find(usr); + if (name != _module.externalNames.end()) { + return "unbridged-type:" + name->second; + } + std::string qualified = qualifiedNameFromUSR(usr); + return "unbridged-type:" + (qualified.empty() ? spelling(node) : qualified); + } + + // JS names for SwiftGenerated members and overload ambiguity. + void resolveNames() { + struct Entry { + std::string id; + bool isProperty; + std::string signature; + }; + std::map, std::vector> + groups; + for (auto& entry : _result.bySymbol) { + Capability& capability = entry.second; + if (capability.tier != Tier::SwiftGenerated || + capability.jsName.empty()) { + continue; + } + const Symbol* symbol = _module.find(entry.first); + bool isProperty = symbol->kind == SymbolKind::InstanceProperty || + symbol->kind == SymbolKind::TypeProperty || + symbol->kind == SymbolKind::Variable || + symbol->kind == SymbolKind::EnumCase; + bool isStatic = symbol->isStatic || + symbol->kind == SymbolKind::EnumCase || + symbol->kind == SymbolKind::Initializer; + std::string signature = std::to_string(capability.parameters.size()); + for (const auto& parameter : capability.parameters) { + signature += "," + jsKind(parameter); + } + groups[{symbol->parentId, capability.jsName, isStatic}].push_back( + Entry{entry.first, isProperty, signature}); + } + + for (auto& group : groups) { + auto& entries = group.second; + bool hasProperty = + std::any_of(entries.begin(), entries.end(), + [](const Entry& e) { return e.isProperty; }); + for (const auto& entry : entries) { + Capability& capability = _result.bySymbol[entry.id]; + if (hasProperty && entries.size() > 1) { + // A JS property and method cannot share a key; the property wins. + if (!entry.isProperty) { + capability.tier = Tier::Unsupported; + capability.reasons = {"js-name-conflict"}; + capability.jsName.clear(); + capability.parameters.clear(); + } + continue; + } + for (const auto& other : entries) { + if (&other != &entry && other.signature == entry.signature) { + capability.ambiguousOverload = true; + } + } + } + } + } + + static std::string jsKind(const BridgedType& type) { + std::string kind; + switch (type.bridge) { + case Bridge::Bool: + kind = "boolean"; + break; + case Bridge::Integer: + case Bridge::Floating: + kind = "number"; + break; + case Bridge::String: + case Bridge::EnumCase: + kind = "string"; + break; + case Bridge::ClassHandle: + case Bridge::StructBox: + kind = "object:" + type.symbolId; + break; + default: + kind = "other"; + break; + } + return type.optional ? kind + "?" : kind; + } + + const Module& _module; + const std::map& _rejections; + Classification _result; +}; + +} // namespace + +std::vector applicableAvailability(const Module& module, + const Symbol& symbol) { + std::string domain = availabilityDomain(module.platform); + std::vector result; + for (const auto& availability : symbol.availability) { + if (availability.domain == "*" || availability.domain == domain) { + result.push_back(&availability); + } + } + return result; +} + +Classification classify(const Module& module, + const std::map& rejections) { + return Classifier(module, rejections).run(); +} + +} // namespace Swift diff --git a/metadata-generator/src/Swift/CapabilityClassifier.h b/metadata-generator/src/Swift/CapabilityClassifier.h new file mode 100644 index 000000000..db0bf8fdd --- /dev/null +++ b/metadata-generator/src/Swift/CapabilityClassifier.h @@ -0,0 +1,104 @@ +#pragma once + +#include +#include +#include + +#include "SwiftIR.h" +#include "SwiftTypes.h" + +namespace Swift { + +// How a declaration is (or is not) reachable from JavaScript. +enum class Tier { + // Objective-C-visible (`c:` USR): served by the existing metadata runtime. + ObjCDirect, + // Callable through a generated Swift thunk. + SwiftGenerated, + // Needs an explicit generic specialization or adapter before it can be + // generated. + SwiftSpecialized, + // Representable in TypeScript but not callable (protocols, type aliases, + // protocol requirements). + TypeOnly, + Unsupported, + // Not an API surface (deinitializers, macros, extension blocks). + NotApplicable, +}; + +const char* toString(Tier tier); + +// How a Swift type crosses into JavaScript. Only types with a bridge other +// than None can appear in generated signatures. +enum class Bridge { + None, + Void, + Bool, + // Integers: JS numbers; values outside +/-(2^53 - 1) throw RangeError + // instead of losing precision. + Integer, + Floating, + String, + // Module class or actor: an owned handle with stable JS identity. + ClassHandle, + // Module struct: a boxed copy; the JS object never aliases another copy. + StructBox, + // Module enum without payloads: its case name as a JS string. + EnumCase, +}; + +struct BridgedType { + Bridge bridge = Bridge::None; + bool optional = false; + // Nominal bridges: the module symbol the type refers to. + std::string symbolId; + TypeNode node; +}; + +struct Capability { + Tier tier = Tier::NotApplicable; + // Stable machine-readable codes, optionally with a detail after ':' + // ("unbridged-type:Foundation.URL"). Codes: + // objc-visible, not-public, unavailable, obsoleted, unknown-kind, + // deinitializer, macro, extension-block, protocol, protocol-requirement, + // type-alias, associated-type, generic, nested-type, noncopyable, + // nonescapable, actor-isolated, + // main-actor, async, operator, subscript, enum-associated-values, + // external-type-extension, owner-not-bridged, missing-owner, + // js-name-conflict, + // inout-parameter, variadic-parameter, closure, tuple, collection, + // existential, opaque-type, metatype, unbridged-type, unparsed-type, + // nested-optional, compiler-rejected + std::vector reasons; + // Property name, method name, or "constructor" for initializers. + std::string jsName; + // Another generated overload with the same JS name accepts the same JS + // argument kinds, so JS-side dispatch must use the signature key. + bool ambiguousOverload = false; + + // Bridges for SwiftGenerated callables: parameters in order, then the + // result (or the property value type). + std::vector parameters; + BridgedType result; +}; + +struct Classification { + std::map bySymbol; + + const Capability* find(const std::string& id) const; +}; + +// `rejections` maps symbol ids the compiler refused (see ProbeVerifier) to +// the compiler's message; those symbols are classified compiler-rejected. +Classification classify( + const Module& module, + const std::map& rejections = {}); + +// Whether `kind` is something JavaScript can call or read. +bool isCallableKind(SymbolKind kind); + +// The availability entries that apply to `module`'s platform. +std::vector applicableAvailability(const Module& module, + const Symbol& symbol); + +} // namespace Swift diff --git a/metadata-generator/src/Swift/CoverageReport.cpp b/metadata-generator/src/Swift/CoverageReport.cpp new file mode 100644 index 000000000..470dbb067 --- /dev/null +++ b/metadata-generator/src/Swift/CoverageReport.cpp @@ -0,0 +1,136 @@ +#include "CoverageReport.h" + +#include +#include +#include + +#include + +namespace Swift { + +namespace { + +const Tier kTiers[] = {Tier::ObjCDirect, Tier::SwiftGenerated, + Tier::SwiftSpecialized, Tier::TypeOnly, + Tier::Unsupported, Tier::NotApplicable}; + +struct Counts { + std::map byTier; + int total = 0; + + void add(Tier tier) { + byTier[tier]++; + total++; + } +}; + +void writeCounts(llvm::json::OStream& out, const Counts& counts) { + out.attribute("total", counts.total); + for (Tier tier : kTiers) { + auto it = counts.byTier.find(tier); + out.attribute(toString(tier), it == counts.byTier.end() ? 0 : it->second); + } +} + +} // namespace + +std::string coverageJSON(const Module& module, + const Classification& classification, + int compilerRuns) { + Counts declarations; + Counts callable; + std::map byKind; + std::map reasons; + + for (const auto& entry : module.symbols) { + const Symbol& symbol = entry.second; + const Capability* capability = classification.find(entry.first); + if (!capability) { + continue; + } + declarations.add(capability->tier); + byKind[toString(symbol.kind)].add(capability->tier); + if (isCallableKind(symbol.kind)) { + callable.add(capability->tier); + } + if (capability->tier == Tier::Unsupported || + capability->tier == Tier::SwiftSpecialized) { + for (const auto& reason : capability->reasons) { + reasons[llvm::StringRef(reason).split(':').first.str()]++; + } + } + } + + std::string result; + llvm::raw_string_ostream stream(result); + llvm::json::OStream out(stream, 2); + out.object([&] { + out.attribute("module", module.name); + out.attributeObject("totals", [&] { + out.attributeObject("declarations", + [&] { writeCounts(out, declarations); }); + out.attributeObject("callable", [&] { writeCounts(out, callable); }); + // Callable through any path: the Objective-C runtime or a thunk. + out.attribute("effectiveCallable", + callable.byTier[Tier::ObjCDirect] + + callable.byTier[Tier::SwiftGenerated]); + if (compilerRuns < 0) { + out.attribute("compilerVerified", false); + } else { + out.attribute("compilerVerified", true); + out.attribute("compilerRuns", compilerRuns); + } + out.attribute("compiledThunks", nullptr); + out.attribute("runtimeTested", nullptr); + }); + out.attributeObject("byKind", [&] { + for (const auto& entry : byKind) { + out.attributeObject(entry.first, + [&] { writeCounts(out, entry.second); }); + } + }); + out.attributeObject("reasons", [&] { + for (const auto& entry : reasons) { + out.attribute(entry.first, entry.second); + } + }); + out.attributeArray("symbols", [&] { + for (const auto& entry : module.symbols) { + const Symbol& symbol = entry.second; + const Capability* capability = classification.find(entry.first); + if (!capability) { + continue; + } + out.object([&] { + out.attribute("id", symbol.preciseId); + out.attribute("path", llvm::join(symbol.pathComponents, ".")); + out.attribute("kind", toString(symbol.kind)); + out.attribute("tier", toString(capability->tier)); + if (!capability->reasons.empty()) { + out.attributeArray("reasons", [&] { + for (const auto& reason : capability->reasons) { + out.value(reason); + } + }); + } + if (!capability->jsName.empty()) { + out.attribute("jsName", capability->jsName); + } + if (capability->ambiguousOverload) { + out.attribute("ambiguousOverload", true); + } + if (symbol.location) { + out.attribute("location", + symbol.location->uri + ":" + + std::to_string(symbol.location->line + 1)); + } + }); + } + }); + }); + stream << "\n"; + stream.flush(); + return result; +} + +} // namespace Swift diff --git a/metadata-generator/src/Swift/CoverageReport.h b/metadata-generator/src/Swift/CoverageReport.h new file mode 100644 index 000000000..39860ff6a --- /dev/null +++ b/metadata-generator/src/Swift/CoverageReport.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +#include "CapabilityClassifier.h" +#include "SwiftIR.h" + +namespace Swift { + +// `.coverage.json`: per-tier and per-kind counts, unsupported reason +// histogram, and the classification of every symbol. `compiledThunks` and +// `runtimeTested` stay null until a later stage measures them. +// +// `compilerRuns` is the number of type-check passes behind `classification` +// (see ProbeVerifier), or -1 when the classification was not compiler +// verified. +std::string coverageJSON(const Module& module, + const Classification& classification, + int compilerRuns = -1); + +} // namespace Swift diff --git a/metadata-generator/src/Swift/FragmentTokens.cpp b/metadata-generator/src/Swift/FragmentTokens.cpp new file mode 100644 index 000000000..7c573096c --- /dev/null +++ b/metadata-generator/src/Swift/FragmentTokens.cpp @@ -0,0 +1,109 @@ +#include "FragmentTokens.h" + +#include + +namespace Swift { +namespace FragmentTokens { + +Tokens tokenize(const Fragments& fragments) { + Tokens tokens; + for (const auto& fragment : fragments) { + // Custom attributes (global actors, property wrappers) arrive as an "@" + // fragment followed by the attribute type's name, which inside types is a + // typeIdentifier (`@MainActor (Message) -> Void`). + if ((fragment.kind == "attribute" || fragment.kind == "typeIdentifier") && + !tokens.empty() && tokens.back().isFragment("attribute") && + tokens.back().text == "@") { + tokens.back().text += fragment.spelling; + tokens.back().precise = fragment.preciseIdentifier; + continue; + } + if (fragment.kind != "text") { + tokens.push_back(Token{Token::Type::Fragment, fragment.kind, + fragment.spelling, fragment.preciseIdentifier}); + continue; + } + + llvm::StringRef text = fragment.spelling; + // Some attributes arrive as plain text ("@backDeployed(before: iOS + // 17.0)\n", "@abi(func f(...))"). Only the name becomes the attribute + // token; its argument list is tokenized normally so consumeAttribute can + // match the parentheses, which may close in a later fragment. + if (text.ltrim().startswith("@")) { + llvm::StringRef rest = text.ltrim(); + size_t nameEnd = 1; + while (nameEnd < rest.size() && + (llvm::isAlnum(rest[nameEnd]) || rest[nameEnd] == '_')) { + nameEnd++; + } + tokens.push_back(Token{Token::Type::Fragment, "attribute", + rest.take_front(nameEnd).str(), ""}); + text = rest.drop_front(nameEnd); + } + + size_t i = 0; + while (i < text.size()) { + char c = text[i]; + if (llvm::isSpace(c)) { + size_t end = i; + while (end < text.size() && llvm::isSpace(text[end])) { + end++; + } + tokens.push_back( + Token{Token::Type::Space, "text", text.slice(i, end).str(), ""}); + i = end; + } else if (text.substr(i).startswith("->")) { + tokens.push_back(Token{Token::Type::Arrow, "text", "->", ""}); + i += 2; + } else if (llvm::StringRef("()[]<>,:?!={}&").contains(c)) { + tokens.push_back( + Token{Token::Type::Punct, "text", std::string(1, c), ""}); + i++; + } else { + size_t end = i; + while (end < text.size() && !llvm::isSpace(text[end]) && + !llvm::StringRef("()[]<>,:?!={}&").contains(text[end]) && + !text.substr(end).startswith("->")) { + end++; + } + llvm::StringRef word = text.slice(i, end); + // "@" inside text starts an attribute whose name may follow as its + // own fragment (": @" + typeIdentifier "MainActor"). + if (word.startswith("@")) { + tokens.push_back( + Token{Token::Type::Fragment, "attribute", word.str(), ""}); + } else { + tokens.push_back(Token{Token::Type::Word, "text", word.str(), ""}); + } + i = end; + } + } + } + return tokens; +} + +TypeRef makeTypeRef(Tokens::const_iterator begin, Tokens::const_iterator end) { + while (begin != end && begin->type == Token::Type::Space) { + ++begin; + } + while (end != begin && std::prev(end)->type == Token::Type::Space) { + --end; + } + + TypeRef type; + for (auto it = begin; it != end; ++it) { + type.spelling += it->text; + if (it->type == Token::Type::Fragment) { + type.fragments.push_back(Fragment{it->kind, it->text, it->precise}); + } else if (!type.fragments.empty() && + type.fragments.back().kind == "text") { + type.fragments.back().spelling += it->text; + } else { + type.fragments.push_back(Fragment{"text", it->text, ""}); + } + } + return type; +} + +} // namespace FragmentTokens +} // namespace Swift diff --git a/metadata-generator/src/Swift/FragmentTokens.h b/metadata-generator/src/Swift/FragmentTokens.h new file mode 100644 index 000000000..d58c8eda4 --- /dev/null +++ b/metadata-generator/src/Swift/FragmentTokens.h @@ -0,0 +1,53 @@ +#pragma once + +#include + +#include +#include + +#include "SwiftIR.h" + +// Symbol graphs carry most semantics (effects, settability, labels, failable +// initializers, actor-ness) only inside `declarationFragments`, where +// structural punctuation is mixed into "text" fragments (e.g. "?) -> "). +// Text fragments are therefore split into single structural tokens before +// parsing. +namespace Swift { +namespace FragmentTokens { + +struct Token { + enum class Type { Fragment, Punct, Space, Word, Arrow }; + Type type; + // Fragment kind for Fragment tokens, "text" otherwise. + std::string kind; + std::string text; + std::string precise; + + bool isPunct(char c) const { + return type == Type::Punct && text.size() == 1 && text[0] == c; + } + bool isFragment(llvm::StringRef fragmentKind) const { + return type == Type::Fragment && kind == fragmentKind; + } + bool isKeyword(llvm::StringRef keyword) const { + return isFragment("keyword") && text == keyword; + } +}; + +using Tokens = std::vector; + +Tokens tokenize(const Fragments& fragments); + +inline bool opens(const Token& token) { + return token.isPunct('(') || token.isPunct('[') || token.isPunct('<'); +} + +inline bool closes(const Token& token) { + return token.isPunct(')') || token.isPunct(']') || token.isPunct('>'); +} + +// The tokens in [begin, end) as a TypeRef, without surrounding whitespace. +TypeRef makeTypeRef(Tokens::const_iterator begin, Tokens::const_iterator end); + +} // namespace FragmentTokens +} // namespace Swift diff --git a/metadata-generator/src/Swift/ProbeEmitter.cpp b/metadata-generator/src/Swift/ProbeEmitter.cpp new file mode 100644 index 000000000..b4c7d668a --- /dev/null +++ b/metadata-generator/src/Swift/ProbeEmitter.cpp @@ -0,0 +1,134 @@ +#include "ProbeEmitter.h" + +#include + +#include "SwiftSource.h" + +namespace Swift { + +namespace { + +// Every line written between begin() and end() maps to that symbol: the +// compiler reports some errors on the declaration line (parameter types), +// others on the statement. +class Writer { + public: + void begin(const std::string& symbolId) { _symbolId = symbolId; } + void end() { _symbolId.clear(); } + + void line(const std::string& text) { + _source += text + "\n"; + _line++; + if (!_symbolId.empty()) { + _map[_line] = _symbolId; + } + } + + ProbeSource finish() { + return ProbeSource{std::move(_source), std::move(_map)}; + } + + private: + std::string _source; + std::map _map; + std::string _symbolId; + int _line = 0; +}; + +} // namespace + +ProbeSource emitProbes(const Module& module, + const Classification& classification) { + Writer out; + out.line( + "// Generated by objc-metadata-generator. Compiler-validation probes " + "for"); + out.line("// the Swift-generated surface of module " + module.name + "."); + out.line("import Foundation"); + out.line("import " + module.name); + std::set overlays; + for (const auto& entry : module.symbols) { + const Capability* capability = classification.find(entry.first); + if (capability && capability->tier == Tier::SwiftGenerated && + !entry.second.declaringModule.empty()) { + overlays.insert(entry.second.declaringModule); + } + } + for (const auto& overlay : overlays) { + out.line("import " + overlay); + } + out.line(""); + + int index = 0; + for (const auto& entry : module.symbols) { + const Symbol& symbol = entry.second; + const Capability* capability = classification.find(entry.first); + if (!capability || capability->tier != Tier::SwiftGenerated) { + continue; + } + + if (isNominalType(symbol.kind)) { + // Bridged types are copied in and out of boxes and handles, which + // requires Copyable (not visible in symbol graphs). + std::string type = qualifiedTypeName(module, symbol); + std::string availability = availabilityCondition(module, symbol); + out.begin(symbol.preciseId); + out.line("// " + symbol.preciseId); + if (!availability.empty()) { + out.line("@available(" + availability + ")"); + } + out.line("func __nsProbe" + std::to_string(index++) + + "(_ value: " + type + ") -> " + type + " { value }"); + out.end(); + out.line(""); + continue; + } + if (!isCallableKind(symbol.kind)) { + continue; + } + + Invocation invocation = describeInvocation(module, symbol, *capability); + std::vector parameters; + if (invocation.needsReceiver) { + parameters.push_back( + "_ receiver: " + + std::string(invocation.receiverIsInout ? "inout " : "") + + invocation.owner); + } + std::vector arguments; + for (size_t i = 0; i < invocation.parameterTypes.size(); i++) { + std::string name = "a" + std::to_string(i); + parameters.push_back("_ " + name + ": " + invocation.parameterTypes[i]); + arguments.push_back(name); + } + if (invocation.isSettable) { + parameters.push_back("_ newValue: " + invocation.resultType); + } + std::string signature; + for (size_t i = 0; i < parameters.size(); i++) { + signature += (i > 0 ? ", " : "") + parameters[i]; + } + + out.begin(symbol.preciseId); + out.line("// " + symbol.preciseId); + // The receiver and parameter types may themselves be gated, so the whole + // probe carries the availability rather than an #available check. + if (!invocation.availability.empty()) { + out.line("@available(" + invocation.availability + ")"); + } + out.line("func __nsProbe" + std::to_string(index++) + "(" + signature + + ")" + (invocation.isThrowing ? " throws" : "") + " {"); + const std::string receiver = "receiver"; + out.line(" let _: " + invocation.resultType + " = " + + invocationExpression(invocation, receiver, arguments)); + if (invocation.isSettable) { + out.line(" " + assignmentStatement(invocation, receiver, "newValue")); + } + out.line("}"); + out.end(); + out.line(""); + } + return out.finish(); +} + +} // namespace Swift diff --git a/metadata-generator/src/Swift/ProbeEmitter.h b/metadata-generator/src/Swift/ProbeEmitter.h new file mode 100644 index 000000000..28691d301 --- /dev/null +++ b/metadata-generator/src/Swift/ProbeEmitter.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +#include "CapabilityClassifier.h" +#include "SwiftIR.h" + +namespace Swift { + +// Swift source that exercises every SwiftGenerated symbol the way a thunk +// will (`let _: Result = try owner.member(label: argument)`). Type-checking it +// against the module proves the IR's labels, types, optionality and effects +// match what the compiler accepts. +struct ProbeSource { + std::string source; + // 1-based source line -> symbol id, for mapping compiler diagnostics back + // to the symbol they reject. + std::map lineToSymbol; +}; + +ProbeSource emitProbes(const Module& module, + const Classification& classification); + +} // namespace Swift diff --git a/metadata-generator/src/Swift/ProbeVerifier.cpp b/metadata-generator/src/Swift/ProbeVerifier.cpp new file mode 100644 index 000000000..337c84521 --- /dev/null +++ b/metadata-generator/src/Swift/ProbeVerifier.cpp @@ -0,0 +1,126 @@ +#include "ProbeVerifier.h" + +#include +#include +#include +#include +#include +#include + +#include "ProbeEmitter.h" + +namespace Swift { + +std::map rejectionsFromLog( + const std::string& log, const std::string& probePath, + const std::map& lineToSymbol, + std::vector& unmapped) { + std::map rejections; + llvm::SmallVector lines; + llvm::StringRef(log).split(lines, '\n'); + for (llvm::StringRef line : lines) { + if (!line.consume_front(probePath) || !line.consume_front(":")) { + continue; + } + auto lineNumber = line.split(':'); + auto column = lineNumber.second.split(':'); + llvm::StringRef message = column.second.trim(); + int number = 0; + if (lineNumber.first.getAsInteger(10, number) || + !message.consume_front("error:")) { + continue; + } + message = message.trim(); + auto symbol = lineToSymbol.find(number); + if (symbol == lineToSymbol.end()) { + unmapped.push_back(std::to_string(number) + ": " + message.str()); + continue; + } + rejections.emplace(symbol->second, message.str()); + } + return rejections; +} + +VerifyResult verifyWithCompiler(const Module& module, + const VerifyOptions& options) { + VerifyResult result; + if (options.compiler.empty()) { + result.failure = "no compiler configured"; + return result; + } + auto program = llvm::sys::findProgramByName(options.compiler[0]); + if (!program) { + result.failure = "compiler '" + options.compiler[0] + "' not found"; + return result; + } + + llvm::SmallString<256> probePath(options.workDirectory); + llvm::sys::path::append(probePath, module.name + ".verify.swift"); + llvm::SmallString<256> logPath(options.workDirectory); + llvm::sys::path::append(logPath, module.name + ".verify.log"); + llvm::sys::fs::create_directories(options.workDirectory); + + // Each pass demotes at least one symbol, so the loop terminates; the bound + // only guards against a compiler that keeps reporting the same errors. + for (int pass = 0; pass < 8; pass++) { + result.classification = classify(module, result.rejections); + ProbeSource probes = emitProbes(module, result.classification); + { + std::error_code error; + llvm::raw_fd_ostream out(probePath, error, llvm::sys::fs::OF_Text); + if (error) { + result.failure = probePath.str().str() + ": " + error.message(); + return result; + } + out << probes.source; + } + + std::vector arguments(options.compiler.begin(), + options.compiler.end()); + arguments.insert(arguments.end(), {"-typecheck", "-sdk", options.sdk, + "-target", options.target}); + for (const auto& path : options.searchPaths) { + arguments.insert(arguments.end(), {"-I", path}); + } + for (const auto& path : options.frameworkSearchPaths) { + arguments.insert(arguments.end(), {"-F", path}); + } + arguments.push_back(probePath.str().str()); + std::vector argv(arguments.begin(), arguments.end()); + std::optional redirects[] = { + std::nullopt, llvm::StringRef(logPath), llvm::StringRef(logPath)}; + std::string executionError; + int status = llvm::sys::ExecuteAndWait(*program, argv, std::nullopt, + redirects, 0, 0, &executionError); + result.compilerRuns++; + if (status < 0) { + result.failure = "compiler did not run: " + executionError; + return result; + } + if (status == 0) { + return result; + } + + auto log = llvm::MemoryBuffer::getFile(logPath); + std::vector unmapped; + auto rejections = + rejectionsFromLog(log ? (*log)->getBuffer().str() : "", + probePath.str().str(), probes.lineToSymbol, unmapped); + if (!unmapped.empty()) { + result.failure = "compiler errors outside any probe (see " + + logPath.str().str() + "): " + unmapped.front(); + return result; + } + size_t before = result.rejections.size(); + result.rejections.insert(rejections.begin(), rejections.end()); + if (result.rejections.size() == before) { + result.failure = "compiler failed without reporting probe errors (see " + + logPath.str().str() + ")"; + return result; + } + } + result.failure = "probes still fail to type-check after repeated demotion"; + return result; +} + +} // namespace Swift diff --git a/metadata-generator/src/Swift/ProbeVerifier.h b/metadata-generator/src/Swift/ProbeVerifier.h new file mode 100644 index 000000000..459764aa2 --- /dev/null +++ b/metadata-generator/src/Swift/ProbeVerifier.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include + +#include "CapabilityClassifier.h" +#include "SwiftIR.h" + +namespace Swift { + +struct VerifyOptions { + // Compiler driver and leading arguments, e.g. {"xcrun", "swiftc"}. + std::vector compiler = {"xcrun", "swiftc"}; + std::string sdk; + std::string target; + // Directories holding the modules' .swiftmodule / frameworks. + std::vector searchPaths; + std::vector frameworkSearchPaths; + // Scratch directory for probe sources and compiler logs. + std::string workDirectory; +}; + +struct VerifyResult { + Classification classification; + // Symbol id -> first compiler error reported against its probe. + std::map rejections; + int compilerRuns = 0; + // Set when verification could not complete: the compiler failed to run, or + // reported errors that map to no probe (e.g. the module cannot be + // imported). + std::string failure; +}; + +// Classifies `module`, type-checks probes for the result, demotes every +// symbol whose probe the compiler rejects, and repeats until the probes +// type-check (demoting a type changes its members' classification). +VerifyResult verifyWithCompiler(const Module& module, + const VerifyOptions& options); + +// "probe.swift:12:7: error: message" lines of `log` for `probePath`, mapped +// through `lineToSymbol`. Errors on unmapped lines go to `unmapped`. +std::map rejectionsFromLog( + const std::string& log, const std::string& probePath, + const std::map& lineToSymbol, + std::vector& unmapped); + +} // namespace Swift diff --git a/metadata-generator/src/Swift/SwiftIR.cpp b/metadata-generator/src/Swift/SwiftIR.cpp new file mode 100644 index 000000000..71361a7c8 --- /dev/null +++ b/metadata-generator/src/Swift/SwiftIR.cpp @@ -0,0 +1,343 @@ +#include "SwiftIR.h" + +#include +#include +#include + +namespace Swift { + +const char* toString(SymbolKind kind) { + switch (kind) { + case SymbolKind::Class: + return "class"; + case SymbolKind::Actor: + return "actor"; + case SymbolKind::Struct: + return "struct"; + case SymbolKind::Enum: + return "enum"; + case SymbolKind::Protocol: + return "protocol"; + case SymbolKind::EnumCase: + return "enumCase"; + case SymbolKind::Initializer: + return "initializer"; + case SymbolKind::Deinitializer: + return "deinitializer"; + case SymbolKind::InstanceMethod: + return "instanceMethod"; + case SymbolKind::TypeMethod: + return "typeMethod"; + case SymbolKind::Operator: + return "operator"; + case SymbolKind::InstanceProperty: + return "instanceProperty"; + case SymbolKind::TypeProperty: + return "typeProperty"; + case SymbolKind::InstanceSubscript: + return "instanceSubscript"; + case SymbolKind::TypeSubscript: + return "typeSubscript"; + case SymbolKind::Function: + return "function"; + case SymbolKind::Variable: + return "variable"; + case SymbolKind::TypeAlias: + return "typeAlias"; + case SymbolKind::AssociatedType: + return "associatedType"; + case SymbolKind::Macro: + return "macro"; + case SymbolKind::Extension: + return "extension"; + case SymbolKind::Unknown: + return "unknown"; + } + return "unknown"; +} + +bool isNominalType(SymbolKind kind) { + switch (kind) { + case SymbolKind::Class: + case SymbolKind::Actor: + case SymbolKind::Struct: + case SymbolKind::Enum: + case SymbolKind::Protocol: + return true; + default: + return false; + } +} + +const char* toString(AccessLevel level) { + switch (level) { + case AccessLevel::Private: + return "private"; + case AccessLevel::FilePrivate: + return "fileprivate"; + case AccessLevel::Internal: + return "internal"; + case AccessLevel::Package: + return "package"; + case AccessLevel::Public: + return "public"; + case AccessLevel::Open: + return "open"; + case AccessLevel::Unknown: + return "unknown"; + } + return "unknown"; +} + +const Symbol* Module::find(const std::string& preciseId) const { + auto it = symbols.find(preciseId); + return it == symbols.end() ? nullptr : &it->second; +} + +bool ModuleSet::hasErrors() const { + for (const auto& diagnostic : diagnostics) { + if (diagnostic.severity == Severity::Error) { + return true; + } + } + return false; +} + +namespace { + +using llvm::json::OStream; + +std::string versionString(const Version& version) { + return std::to_string(version.major) + "." + std::to_string(version.minor) + + "." + std::to_string(version.patch); +} + +void writeStringArray(OStream& out, llvm::StringRef key, + const std::vector& values) { + if (values.empty()) { + return; + } + out.attributeArray(key, [&] { + for (const auto& value : values) { + out.value(value); + } + }); +} + +void writeNonEmpty(OStream& out, llvm::StringRef key, + const std::string& value) { + if (!value.empty()) { + out.attribute(key, value); + } +} + +void writeFlag(OStream& out, llvm::StringRef key, bool value) { + if (value) { + out.attribute(key, true); + } +} + +void writeTypeRef(OStream& out, llvm::StringRef key, const TypeRef& type) { + out.attributeObject(key, [&] { + out.attribute("spelling", type.spelling); + std::vector references; + for (const auto& fragment : type.fragments) { + if (!fragment.preciseIdentifier.empty()) { + references.push_back(fragment.preciseIdentifier); + } + } + writeStringArray(out, "references", references); + }); +} + +void writeConstraints(OStream& out, llvm::StringRef key, + const std::vector& constraints) { + if (constraints.empty()) { + return; + } + out.attributeArray(key, [&] { + for (const auto& constraint : constraints) { + out.object([&] { + out.attribute("kind", constraint.kind); + out.attribute("lhs", constraint.lhs); + out.attribute("rhs", constraint.rhs); + writeNonEmpty(out, "rhsPrecise", constraint.rhsPrecise); + }); + } + }); +} + +void writeSymbol(OStream& out, const Symbol& symbol) { + out.object([&] { + out.attribute("id", symbol.preciseId); + out.attribute("kind", toString(symbol.kind)); + out.attribute("path", llvm::join(symbol.pathComponents, ".")); + out.attribute("name", symbol.name); + out.attribute("access", toString(symbol.access)); + out.attribute("declaration", symbol.declarationText); + writeStringArray(out, "attributes", symbol.attributes); + writeStringArray(out, "modifiers", symbol.modifiers); + writeFlag(out, "static", symbol.isStatic); + writeFlag(out, "synthesized", symbol.isSynthesized); + writeFlag(out, "protocolRequirement", symbol.isProtocolRequirement); + writeFlag(out, "optionalRequirement", symbol.isOptionalRequirement); + + if (!symbol.parameters.empty()) { + out.attributeArray("parameters", [&] { + for (const auto& parameter : symbol.parameters) { + out.object([&] { + writeNonEmpty(out, "label", parameter.label); + writeNonEmpty(out, "internalName", parameter.internalName); + writeTypeRef(out, "type", parameter.type); + writeNonEmpty(out, "modifier", parameter.modifier); + writeStringArray(out, "attributes", parameter.attributes); + writeNonEmpty(out, "default", parameter.defaultValue); + writeFlag(out, "variadic", parameter.isVariadic); + }); + } + }); + } + if (symbol.returnType) { + writeTypeRef(out, "returns", *symbol.returnType); + } + writeFlag(out, "async", symbol.isAsync); + writeFlag(out, "throws", symbol.isThrowing); + writeFlag(out, "rethrows", symbol.isRethrowing); + if (!symbol.thrownType.empty()) { + writeTypeRef(out, "thrownType", symbol.thrownType); + } + writeFlag(out, "failable", symbol.isFailable); + writeFlag(out, "implicitlyUnwrappedFailable", + symbol.isImplicitlyUnwrappedFailable); + if (symbol.valueType) { + writeTypeRef(out, "valueType", *symbol.valueType); + out.attribute("settable", symbol.isSettable); + writeFlag(out, "let", symbol.isLet); + } + if (symbol.aliasedType) { + writeTypeRef(out, "aliasedType", *symbol.aliasedType); + } + + if (!symbol.genericParameters.empty()) { + out.attributeArray("genericParameters", [&] { + for (const auto& parameter : symbol.genericParameters) { + out.object([&] { + out.attribute("name", parameter.name); + out.attribute("depth", parameter.depth); + out.attribute("index", parameter.index); + }); + } + }); + } + writeConstraints(out, "genericConstraints", symbol.genericConstraints); + + if (symbol.extension) { + out.attributeObject("extension", [&] { + out.attribute("extendedModule", symbol.extension->extendedModule); + writeNonEmpty(out, "typeKind", symbol.extension->typeKind); + writeConstraints(out, "constraints", symbol.extension->constraints); + }); + } + + if (!symbol.availability.empty()) { + out.attributeArray("availability", [&] { + for (const auto& availability : symbol.availability) { + out.object([&] { + out.attribute("domain", availability.domain); + if (availability.introduced) { + out.attribute("introduced", + versionString(*availability.introduced)); + } + if (availability.deprecated) { + out.attribute("deprecated", + versionString(*availability.deprecated)); + } + if (availability.obsoleted) { + out.attribute("obsoleted", + versionString(*availability.obsoleted)); + } + writeNonEmpty(out, "message", availability.message); + writeNonEmpty(out, "renamed", availability.renamed); + writeFlag(out, "unconditionallyDeprecated", + availability.isUnconditionallyDeprecated); + writeFlag(out, "unconditionallyUnavailable", + availability.isUnconditionallyUnavailable); + }); + } + }); + } + + if (symbol.location) { + out.attribute("location", symbol.location->uri + ":" + + std::to_string(symbol.location->line) + + ":" + + std::to_string(symbol.location->character)); + } + out.attribute("graph", symbol.sourceGraph); + writeNonEmpty(out, "declaringModule", symbol.declaringModule); + + writeNonEmpty(out, "parent", symbol.parentId); + writeStringArray(out, "members", symbol.memberIds); + writeStringArray(out, "conformances", symbol.conformances); + writeNonEmpty(out, "superclass", symbol.superclassId); + writeNonEmpty(out, "overrides", symbol.overriddenId); + writeNonEmpty(out, "sourceOrigin", symbol.sourceOriginId); + writeStringArray(out, "defaultImplementationOf", + symbol.defaultImplementationOf); + }); +} + +} // namespace + +std::string dumpModuleJSON(const Module& module) { + std::string result; + llvm::raw_string_ostream stream(result); + OStream out(stream, 2); + out.object([&] { + out.attribute("module", module.name); + out.attribute("formatVersion", versionString(module.formatVersion)); + out.attributeObject("platform", [&] { + writeNonEmpty(out, "architecture", module.platform.architecture); + writeNonEmpty(out, "vendor", module.platform.vendor); + writeNonEmpty(out, "operatingSystem", module.platform.operatingSystem); + writeNonEmpty(out, "environment", module.platform.environment); + if (module.platform.minimumVersion) { + out.attribute("minimumVersion", + versionString(*module.platform.minimumVersion)); + } + }); + writeStringArray(out, "graphFiles", module.graphFiles); + writeStringArray(out, "topLevel", module.topLevelIds); + + out.attributeArray("externalTypes", [&] { + for (const auto& entry : module.externalTypes) { + const auto& external = entry.second; + out.object([&] { + out.attribute("id", external.preciseId); + out.attribute("qualifiedName", external.qualifiedName); + writeNonEmpty(out, "extendedModule", external.extendedModule); + writeNonEmpty(out, "typeKind", external.typeKind); + writeStringArray(out, "members", external.memberIds); + writeStringArray(out, "conformances", external.conformances); + }); + } + }); + + out.attributeObject("externalNames", [&] { + for (const auto& entry : module.externalNames) { + out.attribute(entry.first, entry.second); + } + }); + + out.attributeArray("symbols", [&] { + for (const auto& entry : module.symbols) { + writeSymbol(out, entry.second); + } + }); + }); + stream << "\n"; + stream.flush(); + return result; +} + +} // namespace Swift diff --git a/metadata-generator/src/Swift/SwiftIR.h b/metadata-generator/src/Swift/SwiftIR.h new file mode 100644 index 000000000..382955c07 --- /dev/null +++ b/metadata-generator/src/Swift/SwiftIR.h @@ -0,0 +1,274 @@ +#pragma once + +#include +#include +#include +#include + +namespace Swift { + +// One `declarationFragments` entry. `preciseIdentifier` is the USR of the +// referenced declaration for typeIdentifier fragments, empty otherwise. +struct Fragment { + std::string kind; + std::string spelling; + std::string preciseIdentifier; +}; + +using Fragments = std::vector; + +// A type as written in a declaration. Kept unresolved here: `spelling` is the +// source text, `fragments` keep the per-identifier USRs that a type resolver +// needs to map nominal references back to symbols. +struct TypeRef { + std::string spelling; + Fragments fragments; + + bool empty() const { return spelling.empty(); } +}; + +enum class SymbolKind { + Class, + Actor, + Struct, + Enum, + Protocol, + EnumCase, + Initializer, + Deinitializer, + InstanceMethod, + TypeMethod, + Operator, + InstanceProperty, + TypeProperty, + InstanceSubscript, + TypeSubscript, + Function, + Variable, + TypeAlias, + AssociatedType, + Macro, + Extension, + Unknown, +}; + +const char* toString(SymbolKind kind); +bool isNominalType(SymbolKind kind); + +enum class AccessLevel { + Private, + FilePrivate, + Internal, + Package, + Public, + Open, + Unknown +}; + +const char* toString(AccessLevel level); + +struct Version { + int major = 0; + int minor = 0; + int patch = 0; +}; + +struct Availability { + // "iOS", "macOS", ..., or "*" for platform-agnostic attributes. + std::string domain; + std::optional introduced; + std::optional deprecated; + std::optional obsoleted; + std::string message; + std::string renamed; + bool isUnconditionallyDeprecated = false; + bool isUnconditionallyUnavailable = false; +}; + +struct GenericParameter { + std::string name; + int depth = 0; + int index = 0; +}; + +struct GenericConstraint { + // "conformance", "superclass" or "sameType". + std::string kind; + std::string lhs; + std::string rhs; + std::string rhsPrecise; +}; + +struct Parameter { + // Empty when the argument is unlabeled (`_`). + std::string label; + std::string internalName; + TypeRef type; + // Ownership/passing modifier in front of the type: "inout", "borrowing", + // "consuming", "sending", or empty. + std::string modifier; + // Type attributes such as "@escaping", "@autoclosure", "@Sendable". + std::vector attributes; + std::string defaultValue; + bool isVariadic = false; +}; + +struct SourceLocation { + std::string uri; + int line = 0; + int character = 0; +}; + +struct SwiftExtensionInfo { + // Module that declares the extended type (e.g. "Swift" for `extension + // String`). + std::string extendedModule; + std::string typeKind; + std::vector constraints; +}; + +struct Relationship { + std::string kind; + std::string source; + std::string target; + std::string targetFallback; + std::string sourceOriginId; + std::string sourceOriginName; +}; + +struct Symbol { + // Canonical identifier: the USR, except for the `async` variant Swift + // imports for an Objective-C completion-handler method, which shares the + // method's USR and is keyed `#async`. + std::string preciseId; + std::string usr; + SymbolKind kind = SymbolKind::Unknown; + std::string kindIdentifier; + std::vector pathComponents; + // Last path component as Swift spells it, e.g. "scale(by:)" or "x". + std::string name; + // `name` without the argument-label suffix, e.g. "scale". + std::string baseName; + AccessLevel access = AccessLevel::Unknown; + Fragments declaration; + std::string declarationText; + + // Leading declaration attributes ("@MainActor", "nonisolated", ...). + std::vector attributes; + // Declaration modifiers ("static", "class", "mutating", "override", + // "convenience", "final", "required", ...). + std::vector modifiers; + + // Callables (functions, methods, initializers, subscripts, enum case + // payloads). + std::vector parameters; + std::optional returnType; + bool isAsync = false; + bool isThrowing = false; + bool isRethrowing = false; + TypeRef thrownType; + // `init?` / `init!`. + bool isFailable = false; + bool isImplicitlyUnwrappedFailable = false; + + // Properties, variables and subscripts. + std::optional valueType; + bool isSettable = false; + bool isLet = false; + + // Type aliases. + std::optional aliasedType; + + bool isStatic = false; + bool isSynthesized = false; + bool isProtocolRequirement = false; + bool isOptionalRequirement = false; + + std::vector genericParameters; + std::vector genericConstraints; + std::optional extension; + std::vector availability; + // Doc comment lines joined with '\n'. + std::string docComment; + std::optional location; + // Graph file the symbol was read from, relative to the scanned directory. + std::string sourceGraph; + // Set when a cross-import overlay (`_SwiftData_SwiftUI`) rather than the + // module itself declares the symbol; code using it must import the overlay. + std::string declaringModule; + + // Resolved relationships. + std::string parentId; + std::vector memberIds; + std::vector conformances; + std::string superclassId; + std::string overriddenId; + // Requirement or default implementation this member originates from. + std::string sourceOriginId; + std::string sourceOriginName; + std::vector defaultImplementationOf; +}; + +// A type declared outside the module that the module extends +// (e.g. `extension String`). Its members live in Module::symbols. +struct ExternalType { + std::string preciseId; + // Qualified name as reported by the graph, e.g. "Swift.String". + std::string qualifiedName; + std::string extendedModule; + std::string typeKind; + std::vector memberIds; + // Protocols this module makes the type conform to through extensions. + std::vector conformances; +}; + +struct Platform { + std::string architecture; + std::string vendor; + std::string operatingSystem; + std::string environment; + std::optional minimumVersion; +}; + +struct Module { + std::string name; + Platform platform; + Version formatVersion; + std::string generator; + std::vector graphFiles; + + std::map symbols; + std::map externalTypes; + // Qualified names of declarations outside the module that relationships + // point at (conformances, superclasses, extended types), by USR. + std::map externalNames; + std::vector relationships; + // Declarations without a parent inside the module, in source order. + std::vector topLevelIds; + + const Symbol* find(const std::string& preciseId) const; +}; + +enum class Severity { Warning, Error }; + +struct Diagnostic { + Severity severity = Severity::Warning; + // Stable machine-readable code, e.g. "duplicate-symbol". + std::string code; + std::string message; + std::string file; + std::string symbolId; +}; + +struct ModuleSet { + std::map modules; + std::vector diagnostics; + + bool hasErrors() const; +}; + +// Deterministic JSON rendering of a module's IR, used for snapshots and +// `--swift-ir-output`. +std::string dumpModuleJSON(const Module& module); + +} // namespace Swift diff --git a/metadata-generator/src/Swift/SwiftSource.cpp b/metadata-generator/src/Swift/SwiftSource.cpp new file mode 100644 index 000000000..828b90d1c --- /dev/null +++ b/metadata-generator/src/Swift/SwiftSource.cpp @@ -0,0 +1,235 @@ +#include "SwiftSource.h" + +#include + +#include + +namespace Swift { + +std::string declaringModuleName(const Module& module, const Symbol& symbol) { + return symbol.declaringModule.empty() ? module.name : symbol.declaringModule; +} + +std::string qualifiedTypeName(const Module& module, const Symbol& symbol) { + return declaringModuleName(module, symbol) + "." + + llvm::join(symbol.pathComponents, "."); +} + +namespace { + +TypeNode qualify(const TypeNode& node, const Module& module) { + TypeNode result = node; + for (auto& child : result.children) { + child = qualify(child, module); + } + for (auto& child : result.result) { + child = qualify(child, module); + } + for (auto& child : result.thrownType) { + child = qualify(child, module); + } + for (auto& component : result.components) { + for (auto& argument : component.arguments) { + argument = qualify(argument, module); + } + } + if (result.kind == TypeNode::Kind::Nominal) { + const Symbol* symbol = module.find(result.usr()); + if (symbol && isNominalType(symbol->kind)) { + std::vector components; + components.push_back( + TypeNode::Component{declaringModuleName(module, *symbol), "", {}}); + for (const auto& name : symbol->pathComponents) { + components.push_back(TypeNode::Component{name, "", {}}); + } + components.back().usr = symbol->preciseId; + components.back().arguments = result.components.back().arguments; + result.components = std::move(components); + } + } + return result; +} + +std::string ownerTypeText(const Module& module, const Symbol& owner) { + return qualifiedTypeName(module, owner); +} + +std::string typeText(const BridgedType& bridged, const Module& module) { + if (bridged.bridge == Bridge::Void) { + return "Void"; + } + return swiftTypeText(bridged.node, module); +} + +bool isAfter(const Version& a, const Version& b) { + return std::tie(a.major, a.minor, a.patch) > + std::tie(b.major, b.minor, b.patch); +} + +std::string platformName(const Module& module) { + const std::string& os = module.platform.operatingSystem; + if (os == "ios") { + return module.platform.environment == "macabi" ? "macCatalyst" : "iOS"; + } + if (os == "macosx" || os == "macos") { + return "macOS"; + } + if (os == "tvos") { + return "tvOS"; + } + if (os == "watchos") { + return "watchOS"; + } + if (os == "xros" || os == "visionos") { + return "visionOS"; + } + return os; +} + +} // namespace + +std::string swiftTypeText(const TypeNode& node, const Module& module) { + return spelling(qualify(node, module)); +} + +std::string swiftIdentifier(const std::string& name) { + return "`" + name + "`"; +} + +std::string availabilityCondition(const Module& module, const Symbol& symbol) { + // Members inherit their enclosing types' availability. + const Version* introduced = nullptr; + for (const Symbol* current = &symbol; current; + current = current->parentId.empty() ? nullptr + : module.find(current->parentId)) { + for (const Availability* availability : + applicableAvailability(module, *current)) { + if (availability->introduced && + (!introduced || isAfter(*availability->introduced, *introduced))) { + introduced = &*availability->introduced; + } + } + } + if (!introduced || (module.platform.minimumVersion && + !isAfter(*introduced, *module.platform.minimumVersion))) { + return ""; + } + return platformName(module) + " " + std::to_string(introduced->major) + "." + + std::to_string(introduced->minor) + + (introduced->patch ? "." + std::to_string(introduced->patch) : "") + + ", *"; +} + +Invocation describeInvocation(const Module& module, const Symbol& symbol, + const Capability& capability) { + Invocation invocation; + const Symbol* owner = + symbol.parentId.empty() ? nullptr : module.find(symbol.parentId); + invocation.owner = owner ? ownerTypeText(module, *owner) : module.name; + invocation.member = symbol.baseName; + invocation.isThrowing = symbol.isThrowing; + invocation.isSettable = symbol.isSettable; + + for (size_t i = 0; i < symbol.parameters.size(); i++) { + invocation.labels.push_back(symbol.parameters[i].label); + invocation.parameterTypes.push_back( + i < capability.parameters.size() + ? typeText(capability.parameters[i], module) + : ""); + } + + bool valueOwner = owner && (owner->kind == SymbolKind::Struct || + owner->kind == SymbolKind::Enum); + bool mutating = std::find(symbol.modifiers.begin(), symbol.modifiers.end(), + "mutating") != symbol.modifiers.end(); + + switch (symbol.kind) { + case SymbolKind::Initializer: + invocation.form = Invocation::Form::Construct; + invocation.resultType = invocation.owner + (symbol.isFailable ? "?" : ""); + break; + case SymbolKind::InstanceMethod: + invocation.form = Invocation::Form::InstanceMethod; + invocation.needsReceiver = true; + invocation.receiverIsInout = valueOwner && mutating; + break; + case SymbolKind::TypeMethod: + invocation.form = Invocation::Form::StaticMethod; + break; + case SymbolKind::Function: + invocation.form = Invocation::Form::Function; + break; + case SymbolKind::InstanceProperty: + invocation.form = Invocation::Form::InstanceProperty; + invocation.needsReceiver = true; + invocation.receiverIsInout = valueOwner && symbol.isSettable; + break; + case SymbolKind::TypeProperty: + invocation.form = Invocation::Form::StaticProperty; + break; + case SymbolKind::Variable: + invocation.form = Invocation::Form::Variable; + break; + case SymbolKind::EnumCase: + invocation.form = Invocation::Form::EnumCase; + invocation.resultType = invocation.owner; + break; + default: + break; + } + if (invocation.resultType.empty()) { + invocation.resultType = typeText(capability.result, module); + } + + invocation.availability = availabilityCondition(module, symbol); + return invocation; +} + +std::string invocationExpression(const Invocation& invocation, + const std::string& receiver, + const std::vector& arguments) { + std::string argumentList; + for (size_t i = 0; i < arguments.size(); i++) { + if (i > 0) { + argumentList += ", "; + } + const std::string& label = + i < invocation.labels.size() ? invocation.labels[i] : ""; + argumentList += label.empty() ? arguments[i] : label + ": " + arguments[i]; + } + + std::string expression; + std::string member = swiftIdentifier(invocation.member); + switch (invocation.form) { + case Invocation::Form::Construct: + expression = invocation.owner + "(" + argumentList + ")"; + break; + case Invocation::Form::InstanceMethod: + expression = receiver + "." + member + "(" + argumentList + ")"; + break; + case Invocation::Form::StaticMethod: + case Invocation::Form::Function: + expression = invocation.owner + "." + member + "(" + argumentList + ")"; + break; + case Invocation::Form::InstanceProperty: + expression = receiver + "." + member; + break; + case Invocation::Form::StaticProperty: + case Invocation::Form::Variable: + case Invocation::Form::EnumCase: + expression = invocation.owner + "." + member; + break; + } + return invocation.isThrowing ? "try " + expression : expression; +} + +std::string assignmentStatement(const Invocation& invocation, + const std::string& receiver, + const std::string& value) { + std::string target = invocation.form == Invocation::Form::InstanceProperty + ? receiver + : invocation.owner; + return target + "." + swiftIdentifier(invocation.member) + " = " + value; +} + +} // namespace Swift diff --git a/metadata-generator/src/Swift/SwiftSource.h b/metadata-generator/src/Swift/SwiftSource.h new file mode 100644 index 000000000..e0c7a49fb --- /dev/null +++ b/metadata-generator/src/Swift/SwiftSource.h @@ -0,0 +1,76 @@ +#pragma once + +#include +#include + +#include "CapabilityClassifier.h" +#include "SwiftIR.h" +#include "SwiftTypes.h" + +namespace Swift { + +// Swift spelling of `node` with module-local types qualified by module name, +// so generated code is immune to shadowing by other imports. +std::string swiftTypeText(const TypeNode& node, const Module& module); + +// The module that declares `symbol`: its cross-import overlay, if any. +std::string declaringModuleName(const Module& module, const Symbol& symbol); + +// `Module.Outer.Inner` for a module-local type. +std::string qualifiedTypeName(const Module& module, const Symbol& symbol); + +// `name` escaped for use as a Swift identifier or member name. +std::string swiftIdentifier(const std::string& name); + +// How generated Swift code invokes a SwiftGenerated symbol. Shared by the +// compiler-validation probes and the thunks, so a probe that type-checks +// vouches for the thunk's call. +struct Invocation { + enum class Form { + Construct, // Owner(args) + InstanceMethod, // receiver.name(args) + StaticMethod, // Owner.name(args) + Function, // Module.name(args) + InstanceProperty, // receiver.name + StaticProperty, // Owner.name + Variable, // Module.name + EnumCase, // Owner.name + }; + + Form form = Form::Function; + // Qualified owner type, or the module name for top-level declarations. + std::string owner; + std::string member; + std::vector labels; + std::vector parameterTypes; + // Qualified result type ("Void" when there is none). + std::string resultType; + bool isThrowing = false; + bool isSettable = false; + // The receiver must be passed `inout` (mutating members and setters of + // value types). + bool receiverIsInout = false; + bool needsReceiver = false; + // "iOS 16.0, *" when the symbol or an enclosing type is introduced after + // the deployment target, empty otherwise. + std::string availability; +}; + +Invocation describeInvocation(const Module& module, const Symbol& symbol, + const Capability& capability); + +// "iOS 16.0, *" when `symbol` or an enclosing type is introduced after the +// deployment target, empty otherwise. +std::string availabilityCondition(const Module& module, const Symbol& symbol); + +// The expression that reads/calls the symbol, including `try`. +std::string invocationExpression(const Invocation& invocation, + const std::string& receiver, + const std::vector& arguments); + +// The statement that assigns `value` to a settable property or variable. +std::string assignmentStatement(const Invocation& invocation, + const std::string& receiver, + const std::string& value); + +} // namespace Swift diff --git a/metadata-generator/src/Swift/SwiftSurface.cpp b/metadata-generator/src/Swift/SwiftSurface.cpp new file mode 100644 index 000000000..98eed23d0 --- /dev/null +++ b/metadata-generator/src/Swift/SwiftSurface.cpp @@ -0,0 +1,163 @@ +#include "SwiftSurface.h" + +namespace Swift { + +namespace { + +const IntegerWidth kIntegerWidths[] = { + {"i64", "Int", true}, {"i8", "Int8", true}, + {"i16", "Int16", true}, {"i32", "Int32", true}, + {"i64", "Int64", true}, {"u64", "UInt", false}, + {"u8", "UInt8", false}, {"u16", "UInt16", false}, + {"u32", "UInt32", false}, {"u64", "UInt64", false}, +}; + +const char* const kIntegerUSRs[] = { + KnownTypes::kInt, KnownTypes::kInt8, KnownTypes::kInt16, + KnownTypes::kInt32, KnownTypes::kInt64, KnownTypes::kUInt, + KnownTypes::kUInt8, KnownTypes::kUInt16, KnownTypes::kUInt32, + KnownTypes::kUInt64, +}; + +SwiftSurface::MemberKind memberKind(SymbolKind kind) { + switch (kind) { + case SymbolKind::Initializer: + return SwiftSurface::kInitializer; + case SymbolKind::InstanceMethod: + return SwiftSurface::kInstanceMethod; + case SymbolKind::TypeMethod: + return SwiftSurface::kStaticMethod; + case SymbolKind::InstanceProperty: + return SwiftSurface::kInstanceProperty; + case SymbolKind::TypeProperty: + return SwiftSurface::kStaticProperty; + case SymbolKind::Variable: + return SwiftSurface::kVariable; + case SymbolKind::EnumCase: + return SwiftSurface::kEnumCase; + default: + return SwiftSurface::kFunction; + } +} + +} // namespace + +int SwiftSurface::indexOf(const std::string& symbolId) const { + auto it = typeIndex.find(symbolId); + return it == typeIndex.end() ? -1 : it->second; +} + +const TypeNode& unwrappedNode(const BridgedType& type) { + const TypeNode& node = type.node; + if (type.optional && !node.children.empty() && + (node.kind == TypeNode::Kind::Optional || + node.kind == TypeNode::Kind::ImplicitlyUnwrappedOptional)) { + return node.children[0]; + } + return node; +} + +const IntegerWidth* integerWidth(const BridgedType& type) { + const std::string& usr = unwrappedNode(type).usr(); + for (size_t i = 0; i < sizeof(kIntegerUSRs) / sizeof(kIntegerUSRs[0]); i++) { + if (usr == kIntegerUSRs[i]) { + return &kIntegerWidths[i]; + } + } + return nullptr; +} + +std::string signatureCode(const SwiftSurface& surface, + const BridgedType& type) { + std::string code; + switch (type.bridge) { + case Bridge::Void: + code = "v"; + break; + case Bridge::Bool: + code = "b"; + break; + case Bridge::Integer: + code = integerWidth(type) ? integerWidth(type)->code : "i64"; + break; + case Bridge::Floating: + code = unwrappedNode(type).usr() == KnownTypes::kFloat ? "f32" : "f64"; + break; + case Bridge::String: + code = "s"; + break; + case Bridge::ClassHandle: + case Bridge::StructBox: + code = "o" + std::to_string(surface.indexOf(type.symbolId)); + break; + case Bridge::EnumCase: + code = "e" + std::to_string(surface.indexOf(type.symbolId)); + break; + case Bridge::None: + code = "?"; + break; + } + return type.optional ? code + "?" : code; +} + +SwiftSurface describeSurface(const Module& module, + const Classification& classification) { + SwiftSurface surface; + for (const auto& entry : module.symbols) { + const Symbol& symbol = entry.second; + const Capability* capability = classification.find(entry.first); + if (!capability || capability->tier != Tier::SwiftGenerated || + !isNominalType(symbol.kind) || symbol.kind == SymbolKind::Protocol) { + continue; + } + SwiftSurface::TypeKind kind = + symbol.kind == SymbolKind::Struct ? SwiftSurface::kStruct + : symbol.kind == SymbolKind::Enum ? SwiftSurface::kEnum + : symbol.kind == SymbolKind::Actor ? SwiftSurface::kActor + : SwiftSurface::kClass; + int index = static_cast(surface.types.size()); + surface.types.push_back(SwiftSurface::Type{&symbol, index, kind, -1}); + surface.typeIndex[symbol.preciseId] = index; + } + for (auto& type : surface.types) { + type.superIndex = surface.indexOf(type.symbol->superclassId); + } + + for (const auto& entry : module.symbols) { + const Symbol& symbol = entry.second; + const Capability* capability = classification.find(entry.first); + if (!capability || capability->tier != Tier::SwiftGenerated || + !isCallableKind(symbol.kind)) { + continue; + } + const Symbol* owner = + symbol.parentId.empty() ? nullptr : module.find(symbol.parentId); + + SwiftSurface::Member member; + member.symbol = &symbol; + member.capability = capability; + member.owner = owner ? surface.indexOf(owner->preciseId) : -1; + member.kind = memberKind(symbol.kind); + member.flags = + (symbol.isThrowing ? SwiftSurface::kThrows : 0) | + (symbol.isSettable && member.kind != SwiftSurface::kEnumCase + ? SwiftSurface::kSettable + : 0) | + (capability->ambiguousOverload ? SwiftSurface::kAmbiguous : 0); + member.result = capability->result; + if (member.kind == SwiftSurface::kEnumCase) { + member.result.bridge = Bridge::EnumCase; + member.result.symbolId = owner ? owner->preciseId : ""; + member.result.optional = false; + } + for (size_t i = 0; i < capability->parameters.size(); i++) { + member.signature += (i > 0 ? "," : "") + + signatureCode(surface, capability->parameters[i]); + } + member.signature += ">" + signatureCode(surface, member.result); + surface.members.push_back(std::move(member)); + } + return surface; +} + +} // namespace Swift diff --git a/metadata-generator/src/Swift/SwiftSurface.h b/metadata-generator/src/Swift/SwiftSurface.h new file mode 100644 index 000000000..6f84807cd --- /dev/null +++ b/metadata-generator/src/Swift/SwiftSurface.h @@ -0,0 +1,78 @@ +#pragma once + +#include +#include +#include + +#include "CapabilityClassifier.h" +#include "SwiftIR.h" + +namespace Swift { + +// What a module registers with the runtime: the shared model behind the +// thunks (ThunkEmitter) and the TypeScript declarations +// (SwiftDefinitionWriter), so the two cannot disagree. Kinds, flags and +// signature codes are those of NativeScript/runtime/SwiftInterop.h. +struct SwiftSurface { + enum TypeKind { kClass = 0, kActor = 1, kStruct = 2, kEnum = 3 }; + enum MemberKind { + kInitializer = 0, + kInstanceMethod = 1, + kStaticMethod = 2, + kInstanceProperty = 3, + kStaticProperty = 4, + kFunction = 5, + kVariable = 6, + kEnumCase = 7, + }; + enum Flags { kThrows = 1 << 0, kSettable = 1 << 1, kAmbiguous = 1 << 2 }; + + struct Type { + const Symbol* symbol; + int index; + TypeKind kind; + // Type index of the registered superclass, or -1. + int superIndex; + }; + + struct Member { + const Symbol* symbol; + const Capability* capability; + // Type index, or -1 for module-level functions and variables. + int owner; + MemberKind kind; + int flags; + std::string signature; + // The value the member produces: the owner for initializers and enum + // cases, the property type for properties. + BridgedType result; + }; + + std::vector types; + std::vector members; + + // Type index of `symbolId`, or -1 when the type is not registered. + int indexOf(const std::string& symbolId) const; + + std::map typeIndex; +}; + +SwiftSurface describeSurface(const Module& module, + const Classification& classification); + +// Signature code of one value ("i64", "o3?", ...). +std::string signatureCode(const SwiftSurface& surface, const BridgedType& type); + +// Signed/unsigned integer width of an Integer bridge: {code, Swift type, +// signed}. +struct IntegerWidth { + const char* code; + const char* swiftType; + bool isSigned; +}; +const IntegerWidth* integerWidth(const BridgedType& type); + +// The type a BridgedType names without its optional wrapper. +const TypeNode& unwrappedNode(const BridgedType& type); + +} // namespace Swift diff --git a/metadata-generator/src/Swift/SwiftTypes.cpp b/metadata-generator/src/Swift/SwiftTypes.cpp new file mode 100644 index 000000000..97a60efad --- /dev/null +++ b/metadata-generator/src/Swift/SwiftTypes.cpp @@ -0,0 +1,663 @@ +#include "SwiftTypes.h" + +#include + +#include "FragmentTokens.h" + +namespace Swift { + +using namespace FragmentTokens; + +const std::string& TypeNode::usr() const { + static const std::string empty; + return components.empty() ? empty : components.back().usr; +} + +bool TypeNode::hasAttribute(const std::string& attribute) const { + for (const auto& candidate : attributes) { + if (candidate == attribute) { + return true; + } + } + return false; +} + +const char* toString(TypeNode::Kind kind) { + switch (kind) { + case TypeNode::Kind::Nominal: + return "nominal"; + case TypeNode::Kind::GenericParameter: + return "genericParameter"; + case TypeNode::Kind::Optional: + return "optional"; + case TypeNode::Kind::ImplicitlyUnwrappedOptional: + return "implicitlyUnwrappedOptional"; + case TypeNode::Kind::Array: + return "array"; + case TypeNode::Kind::Dictionary: + return "dictionary"; + case TypeNode::Kind::Tuple: + return "tuple"; + case TypeNode::Kind::Function: + return "function"; + case TypeNode::Kind::Metatype: + return "metatype"; + case TypeNode::Kind::Existential: + return "existential"; + case TypeNode::Kind::Opaque: + return "opaque"; + case TypeNode::Kind::Composition: + return "composition"; + case TypeNode::Kind::Void: + return "void"; + case TypeNode::Kind::Unknown: + return "unknown"; + } + return "unknown"; +} + +namespace { + +bool isWord(const Token& token, llvm::StringRef word) { + return (token.type == Token::Type::Word || token.isFragment("keyword")) && + token.text == word; +} + +bool isName(const Token& token) { + return token.isFragment("typeIdentifier") || + token.isFragment("genericParameter") || + token.isFragment("identifier") || + (token.isFragment("keyword") && + (token.text == "Self" || token.text == "Any" || + token.text == "AnyObject")) || + (token.type == Token::Type::Word && !token.text.empty() && + (llvm::isAlpha(token.text[0]) || token.text[0] == '_')); +} + +class TypeParser { + public: + TypeParser(const Tokens& tokens, const std::set& genericNames) + : _tokens(tokens), _genericNames(genericNames) {} + + TypeNode parse(bool* complete) { + TypeNode node = parseType(); + skipSpaces(); + if (complete) { + *complete = !_failed && atEnd(); + } + return node; + } + + private: + bool atEnd() const { return _pos >= _tokens.size(); } + const Token& peek() const { return _tokens[_pos]; } + + void skipSpaces() { + while (!atEnd() && peek().type == Token::Type::Space) { + _pos++; + } + } + + bool acceptPunct(char c) { + skipSpaces(); + if (!atEnd() && peek().isPunct(c)) { + _pos++; + return true; + } + return false; + } + + TypeNode unknown(std::string text) { + _failed = true; + TypeNode node; + node.kind = TypeNode::Kind::Unknown; + node.text = std::move(text); + return node; + } + + std::string consumeAttribute() { + std::string attribute = peek().text; + bool abuts = !attribute.empty() && !llvm::isSpace(attribute.back()); + attribute = llvm::StringRef(attribute).trim().str(); + _pos++; + if (abuts && !atEnd() && peek().isPunct('(')) { + int depth = 0; + while (!atEnd()) { + const Token& token = _tokens[_pos++]; + attribute += token.text; + if (opens(token)) { + depth++; + } else if (closes(token) && --depth == 0) { + break; + } + } + } + return attribute; + } + + TypeNode parseType() { + std::vector attributes; + std::vector modifiers; + while (true) { + skipSpaces(); + if (atEnd()) { + break; + } + const Token& token = peek(); + if (token.isFragment("attribute") || + (token.isFragment("keyword") && + llvm::StringRef(token.text).startswith("nonisolated")) || + isWord(token, "nonisolated")) { + // `nonisolated(nonsending)` qualifies closure types like an attribute. + attributes.push_back(consumeAttribute()); + } else if (isWord(token, "inout") || isWord(token, "borrowing") || + isWord(token, "consuming") || isWord(token, "sending") || + isWord(token, "__owned") || isWord(token, "__shared") || + isWord(token, "isolated") || isWord(token, "repeat") || + isWord(token, "each")) { + modifiers.push_back(token.text); + _pos++; + } else { + break; + } + } + + TypeNode node; + skipSpaces(); + if (!atEnd() && (isWord(peek(), "some") || isWord(peek(), "any"))) { + bool opaque = peek().text == "some"; + _pos++; + node.kind = opaque ? TypeNode::Kind::Opaque : TypeNode::Kind::Existential; + node.children.push_back(parseComposition()); + } else { + node = parseComposition(); + } + + node.attributes.insert(node.attributes.begin(), attributes.begin(), + attributes.end()); + if (!modifiers.empty()) { + node.modifier = llvm::join(modifiers, " "); + } + if (llvm::StringRef(node.modifier).contains("each")) { + // Parameter packs are not modeled. + _failed = true; + } + return node; + } + + TypeNode parseComposition() { + TypeNode first = parsePostfix(parsePrimary()); + if (!acceptPunct('&')) { + return first; + } + TypeNode composition; + composition.kind = TypeNode::Kind::Composition; + composition.children.push_back(std::move(first)); + do { + composition.children.push_back(parsePostfix(parsePrimary())); + } while (acceptPunct('&')); + return composition; + } + + TypeNode parsePostfix(TypeNode node) { + while (true) { + if (atEnd()) { + return node; + } + const Token& token = peek(); + if (token.isPunct('?') || token.isPunct('!')) { + TypeNode wrapper; + wrapper.kind = token.isPunct('?') + ? TypeNode::Kind::Optional + : TypeNode::Kind::ImplicitlyUnwrappedOptional; + wrapper.children.push_back(std::move(node)); + node = std::move(wrapper); + _pos++; + } else if (token.type == Token::Type::Word && + (token.text == ".Type" || token.text == ".Protocol")) { + TypeNode wrapper; + wrapper.kind = TypeNode::Kind::Metatype; + wrapper.text = token.text.substr(1); + wrapper.children.push_back(std::move(node)); + node = std::move(wrapper); + _pos++; + } else { + return node; + } + } + } + + // Parses `(`-delimited elements; the opening parenthesis is consumed. + std::vector parseParenthesized(std::vector& labels, + bool& anyLabel) { + std::vector elements; + anyLabel = false; + skipSpaces(); + if (acceptPunct(')')) { + return elements; + } + while (true) { + skipSpaces(); + std::string label; + // `label: Type` inside tuples (and argument-labeled closure types). + if (!atEnd() && _pos + 1 < _tokens.size() && + (peek().type == Token::Type::Word || + peek().isFragment("identifier") || + peek().isFragment("externalParam") || + peek().isFragment("internalParam"))) { + size_t lookahead = _pos + 1; + while (lookahead < _tokens.size() && + _tokens[lookahead].type == Token::Type::Space) { + lookahead++; + } + if (lookahead < _tokens.size() && _tokens[lookahead].isPunct(':')) { + label = peek().text; + anyLabel = true; + _pos = lookahead + 1; + } + } + labels.push_back(label); + elements.push_back(parseType()); + if (acceptPunct(',')) { + continue; + } + if (acceptPunct(')')) { + return elements; + } + _failed = true; + return elements; + } + } + + TypeNode parsePrimary() { + skipSpaces(); + if (atEnd()) { + return unknown(""); + } + const Token& token = peek(); + + if (token.isPunct('(')) { + _pos++; + std::vector labels; + bool anyLabel = false; + std::vector elements = parseParenthesized(labels, anyLabel); + + skipSpaces(); + bool isFunction = + !atEnd() && + (isWord(peek(), "async") || isWord(peek(), "throws") || + isWord(peek(), "rethrows") || peek().type == Token::Type::Arrow); + if (isFunction) { + TypeNode function; + function.kind = TypeNode::Kind::Function; + function.children = std::move(elements); + while (true) { + skipSpaces(); + if (atEnd()) { + break; + } + if (isWord(peek(), "async")) { + function.isAsync = true; + _pos++; + } else if (isWord(peek(), "throws") || isWord(peek(), "rethrows")) { + function.isThrowing = true; + _pos++; + if (!atEnd() && peek().isPunct('(')) { + _pos++; + function.thrownType.push_back(parseType()); + if (!acceptPunct(')')) { + _failed = true; + } + } + } else { + break; + } + } + skipSpaces(); + if (atEnd() || peek().type != Token::Type::Arrow) { + _failed = true; + return function; + } + _pos++; + function.result.push_back(parseType()); + return function; + } + + if (elements.empty()) { + TypeNode voidNode; + voidNode.kind = TypeNode::Kind::Void; + return voidNode; + } + if (elements.size() == 1 && !anyLabel) { + return std::move(elements.front()); + } + TypeNode tuple; + tuple.kind = TypeNode::Kind::Tuple; + tuple.children = std::move(elements); + tuple.labels = std::move(labels); + return tuple; + } + + if (token.isPunct('[')) { + _pos++; + TypeNode key = parseType(); + TypeNode node; + if (acceptPunct(':')) { + node.kind = TypeNode::Kind::Dictionary; + node.children.push_back(std::move(key)); + node.children.push_back(parseType()); + } else { + node.kind = TypeNode::Kind::Array; + node.children.push_back(std::move(key)); + } + if (!acceptPunct(']')) { + _failed = true; + } + return node; + } + + if (isName(token)) { + return parseNominal(); + } + + _pos++; + return unknown(token.text); + } + + TypeNode parseNominal() { + TypeNode node; + node.kind = TypeNode::Kind::Nominal; + while (true) { + const Token& token = peek(); + TypeNode::Component component; + component.name = token.text; + component.usr = token.precise; + _pos++; + if (!atEnd() && peek().isPunct('<')) { + _pos++; + do { + component.arguments.push_back(parseType()); + } while (acceptPunct(',')); + if (!acceptPunct('>')) { + _failed = true; + } + } + node.components.push_back(std::move(component)); + + if (atEnd() || peek().type != Token::Type::Word) { + break; + } + llvm::StringRef word = peek().text; + if (word == ".") { + // `Outer` "." `Inner`, the inner name being its own fragment. + if (_pos + 1 < _tokens.size() && isName(_tokens[_pos + 1])) { + _pos++; + continue; + } + break; + } + if (word.startswith(".") && word != ".Type" && word != ".Protocol" && + word.size() > 1 && (llvm::isAlpha(word[1]) || word[1] == '_')) { + // `Outer.Inner` written as one text run after the outer name. + for (llvm::StringRef rest = word.drop_front(); !rest.empty();) { + auto split = rest.split('.'); + node.components.push_back( + TypeNode::Component{split.first.str(), "", {}}); + rest = split.second; + } + _pos++; + } + break; + } + return normalize(std::move(node)); + } + + TypeNode normalize(TypeNode node) { + const std::string& first = node.components.front().name; + if (first == "Self" || _genericNames.count(first)) { + node.kind = TypeNode::Kind::GenericParameter; + return node; + } + if (node.components.size() != 1) { + return node; + } + TypeNode::Component& component = node.components.front(); + auto wrap = [&](TypeNode::Kind kind, size_t arity) -> TypeNode { + if (component.arguments.size() != arity) { + return node; + } + TypeNode wrapper; + wrapper.kind = kind; + wrapper.children = std::move(component.arguments); + return wrapper; + }; + const std::string& usr = component.usr; + if (usr == KnownTypes::kOptional) { + return wrap(TypeNode::Kind::Optional, 1); + } + if (usr == KnownTypes::kArray) { + return wrap(TypeNode::Kind::Array, 1); + } + if (usr == KnownTypes::kDictionary) { + return wrap(TypeNode::Kind::Dictionary, 2); + } + if (usr == KnownTypes::kVoid || (usr.empty() && component.name == "Void")) { + TypeNode voidNode; + voidNode.kind = TypeNode::Kind::Void; + return voidNode; + } + if (component.name == "Any" || component.name == "AnyObject") { + TypeNode existential; + existential.kind = TypeNode::Kind::Existential; + existential.children.push_back(std::move(node)); + return existential; + } + return node; + } + + const Tokens& _tokens; + const std::set& _genericNames; + size_t _pos = 0; + bool _failed = false; +}; + +std::string spellComponents(const TypeNode& node) { + std::string out; + for (size_t i = 0; i < node.components.size(); i++) { + const auto& component = node.components[i]; + if (i > 0) { + out += "."; + } + out += component.name; + if (!component.arguments.empty()) { + out += "<"; + for (size_t j = 0; j < component.arguments.size(); j++) { + if (j > 0) { + out += ", "; + } + out += spelling(component.arguments[j]); + } + out += ">"; + } + } + return out; +} + +// Postfix operators bind tighter than function arrows and compositions. +std::string spellOperand(const TypeNode& node) { + std::string text = spelling(node); + bool needsParens = node.kind == TypeNode::Kind::Function || + node.kind == TypeNode::Kind::Composition || + node.kind == TypeNode::Kind::Existential || + node.kind == TypeNode::Kind::Opaque; + return needsParens ? "(" + text + ")" : text; +} + +} // namespace + +TypeNode parseType(const TypeRef& type, + const std::set& genericNames, bool* complete) { + Tokens tokens = tokenize(type.fragments); + TypeParser parser(tokens, genericNames); + return parser.parse(complete); +} + +std::string spelling(const TypeNode& node) { + std::string prefix; + for (const auto& attribute : node.attributes) { + prefix += attribute + " "; + } + if (!node.modifier.empty()) { + prefix += node.modifier + " "; + } + + std::string body; + switch (node.kind) { + case TypeNode::Kind::Nominal: + case TypeNode::Kind::GenericParameter: + body = spellComponents(node); + break; + case TypeNode::Kind::Optional: + body = spellOperand(node.children[0]) + "?"; + break; + case TypeNode::Kind::ImplicitlyUnwrappedOptional: + body = spellOperand(node.children[0]) + "!"; + break; + case TypeNode::Kind::Array: + body = "[" + spelling(node.children[0]) + "]"; + break; + case TypeNode::Kind::Dictionary: + body = "[" + spelling(node.children[0]) + ": " + + spelling(node.children[1]) + "]"; + break; + case TypeNode::Kind::Tuple: { + body = "("; + for (size_t i = 0; i < node.children.size(); i++) { + if (i > 0) { + body += ", "; + } + if (i < node.labels.size() && !node.labels[i].empty()) { + body += node.labels[i] + ": "; + } + body += spelling(node.children[i]); + } + body += ")"; + break; + } + case TypeNode::Kind::Function: { + body = "("; + for (size_t i = 0; i < node.children.size(); i++) { + if (i > 0) { + body += ", "; + } + body += spelling(node.children[i]); + } + body += ")"; + if (node.isAsync) { + body += " async"; + } + if (node.isThrowing) { + body += " throws"; + if (!node.thrownType.empty()) { + body += "(" + spelling(node.thrownType[0]) + ")"; + } + } + body += " -> " + (node.result.empty() ? std::string("Void") + : spelling(node.result[0])); + break; + } + case TypeNode::Kind::Metatype: + body = spellOperand(node.children[0]) + "." + + (node.text.empty() ? "Type" : node.text); + break; + case TypeNode::Kind::Existential: + if (node.children.size() == 1 && + node.children[0].kind == TypeNode::Kind::Nominal && + node.children[0].components.size() == 1 && + (node.children[0].components[0].name == "Any" || + node.children[0].components[0].name == "AnyObject")) { + body = node.children[0].components[0].name; + } else { + body = "any " + spelling(node.children[0]); + } + break; + case TypeNode::Kind::Opaque: + body = "some " + spelling(node.children[0]); + break; + case TypeNode::Kind::Composition: { + for (size_t i = 0; i < node.children.size(); i++) { + if (i > 0) { + body += " & "; + } + body += spelling(node.children[i]); + } + break; + } + case TypeNode::Kind::Void: + body = "Void"; + break; + case TypeNode::Kind::Unknown: + body = node.text; + break; + } + return prefix + body; +} + +std::string qualifiedNameFromUSR(const std::string& usr) { + static const std::pair standard[] = { + {"s:Sb", "Swift.Bool"}, {"s:Si", "Swift.Int"}, + {"s:Su", "Swift.UInt"}, {"s:Sf", "Swift.Float"}, + {"s:Sd", "Swift.Double"}, {"s:SS", "Swift.String"}, + {"s:SJ", "Swift.Character"}, {"s:Sq", "Swift.Optional"}, + {"s:Sa", "Swift.Array"}, {"s:SD", "Swift.Dictionary"}, + {"s:Sh", "Swift.Set"}, + }; + for (const auto& entry : standard) { + if (usr == entry.first) { + return entry.second; + } + } + // `s:` followed by length-prefixed identifiers (module first) and one + // declaration-kind letter: s:10Foundation4DataV -> Foundation.Data. + llvm::StringRef rest = usr; + if (!rest.consume_front("s:")) { + return ""; + } + std::vector names; + // A leading `s` abbreviates the Swift module: s:s5Int64V. + if (rest.consume_front("s")) { + names.push_back("Swift"); + } + while (!rest.empty() && llvm::isDigit(rest.front())) { + size_t length = 0; + while (!rest.empty() && llvm::isDigit(rest.front())) { + length = length * 10 + (rest.front() - '0'); + rest = rest.drop_front(); + } + if (length == 0 || length > rest.size()) { + return ""; + } + names.push_back(rest.take_front(length).str()); + rest = rest.drop_front(length); + } + if (names.size() < 2 || rest.size() != 1 || + !llvm::StringRef("VCOPa").contains(rest.front())) { + return ""; + } + return llvm::join(names, "."); +} + +std::set genericNamesInScope(const Module& module, + const Symbol& symbol) { + std::set names; + for (const Symbol* current = &symbol; current; + current = current->parentId.empty() ? nullptr + : module.find(current->parentId)) { + for (const auto& parameter : current->genericParameters) { + names.insert(parameter.name); + } + } + return names; +} + +} // namespace Swift diff --git a/metadata-generator/src/Swift/SwiftTypes.h b/metadata-generator/src/Swift/SwiftTypes.h new file mode 100644 index 000000000..8b7d64617 --- /dev/null +++ b/metadata-generator/src/Swift/SwiftTypes.h @@ -0,0 +1,118 @@ +#pragma once + +#include +#include +#include + +#include "SwiftIR.h" + +namespace Swift { + +// A Swift type as a tree, parsed from a TypeRef's fragments. +struct TypeNode { + enum class Kind { + // A named type, possibly nested (`AttributedString.Index`) and generic + // (`Binding`). Optional, Array and Dictionary spelled as named + // generics are normalized to their own kinds. + Nominal, + // A generic parameter in scope, `Self`, or a member of one (`T.Value`). + GenericParameter, + Optional, + ImplicitlyUnwrappedOptional, + Array, + Dictionary, + Tuple, + Function, + Metatype, + // `any P` (also `Any`, `AnyObject`). + Existential, + // `some P`. + Opaque, + // `P & Q`. + Composition, + Void, + // Anything the parser does not model (parameter packs, `~Copyable`); + // `text` holds the spelling. + Unknown, + }; + + struct Component { + std::string name; + std::string usr; + std::vector arguments; + }; + + Kind kind = Kind::Unknown; + // Nominal: one entry per dot-separated name; GenericParameter: its name(s). + std::vector components; + // Element/wrapped types, tuple elements, function parameters, composition + // members, dictionary key and value. + std::vector children; + std::vector labels; + // Function result; empty for other kinds. + std::vector result; + std::vector thrownType; + bool isAsync = false; + bool isThrowing = false; + // "@escaping", "@Sendable", "@MainActor", "@convention(c)", ... + std::vector attributes; + // "inout", "borrowing", "consuming", "sending", "repeat each". + std::string modifier; + std::string text; + + // USR of the last component (Nominal only). + const std::string& usr() const; + bool hasAttribute(const std::string& attribute) const; +}; + +const char* toString(TypeNode::Kind kind); + +// Parses `type`. Names in `genericNames` (and `Self`) are generic parameters. +// `complete` is cleared when trailing tokens could not be parsed; the +// returned node then describes only a prefix. +TypeNode parseType(const TypeRef& type, + const std::set& genericNames, + bool* complete = nullptr); + +// Canonical Swift spelling of `node`. +std::string spelling(const TypeNode& node); + +// Qualified name encoded in a simple nominal USR ("s:10Foundation4DataV" -> +// "Foundation.Data"), or "" when the USR is not of that shape. +std::string qualifiedNameFromUSR(const std::string& usr); + +// Generic parameter names in scope for `symbol`: its own and those of every +// enclosing declaration. +std::set genericNamesInScope(const Module& module, + const Symbol& symbol); + +// Well-known USRs of standard library and Foundation types. +namespace KnownTypes { +constexpr const char* kBool = "s:Sb"; +constexpr const char* kInt = "s:Si"; +constexpr const char* kInt8 = "s:s4Int8V"; +constexpr const char* kInt16 = "s:s5Int16V"; +constexpr const char* kInt32 = "s:s5Int32V"; +constexpr const char* kInt64 = "s:s5Int64V"; +constexpr const char* kUInt = "s:Su"; +constexpr const char* kUInt8 = "s:s5UInt8V"; +constexpr const char* kUInt16 = "s:s6UInt16V"; +constexpr const char* kUInt32 = "s:s6UInt32V"; +constexpr const char* kUInt64 = "s:s6UInt64V"; +constexpr const char* kFloat = "s:Sf"; +constexpr const char* kDouble = "s:Sd"; +constexpr const char* kCGFloat = "s:14CoreFoundation7CGFloatV"; +constexpr const char* kString = "s:SS"; +constexpr const char* kCharacter = "s:SJ"; +constexpr const char* kOptional = "s:Sq"; +constexpr const char* kArray = "s:Sa"; +constexpr const char* kDictionary = "s:SD"; +constexpr const char* kSet = "s:Sh"; +constexpr const char* kVoid = "s:s4Voida"; +constexpr const char* kURL = "s:10Foundation3URLV"; +constexpr const char* kData = "s:10Foundation4DataV"; +constexpr const char* kDate = "s:10Foundation4DateV"; +constexpr const char* kError = "s:s5ErrorP"; +} // namespace KnownTypes + +} // namespace Swift diff --git a/metadata-generator/src/Swift/SymbolGraphLoader.cpp b/metadata-generator/src/Swift/SymbolGraphLoader.cpp new file mode 100644 index 000000000..6af364286 --- /dev/null +++ b/metadata-generator/src/Swift/SymbolGraphLoader.cpp @@ -0,0 +1,1279 @@ +#include "SymbolGraphLoader.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "FragmentTokens.h" + +namespace Swift { + +namespace { + +namespace fs = llvm::sys::fs; +namespace path = llvm::sys::path; +using llvm::json::Array; +using llvm::json::Object; + +void report(std::vector& diagnostics, Severity severity, + std::string code, std::string message, std::string file, + std::string symbolId = "") { + diagnostics.push_back(Diagnostic{severity, std::move(code), + std::move(message), std::move(file), + std::move(symbolId)}); +} + +std::string str(const Object* object, llvm::StringRef key) { + if (!object) { + return ""; + } + auto value = object->getString(key); + return value ? value->str() : ""; +} + +int integer(const Object* object, llvm::StringRef key) { + if (!object) { + return 0; + } + auto value = object->getInteger(key); + return value ? static_cast(*value) : 0; +} + +bool boolean(const Object* object, llvm::StringRef key) { + if (!object) { + return false; + } + auto value = object->getBoolean(key); + return value && *value; +} + +std::optional version(const Object* object) { + if (!object) { + return std::nullopt; + } + return Version{integer(object, "major"), integer(object, "minor"), + integer(object, "patch")}; +} + +bool isGraphFileName(llvm::StringRef fileName) { + return fileName.endswith(".symbols.json") || + fileName.endswith(".symbolgraph"); +} + +// --- Declaration fragment parsing ------------------------------------------- + +using namespace FragmentTokens; + +bool isVoid(const TypeRef& type) { + return type.spelling == "()" || type.spelling == "Void"; +} + +class DeclarationParser { + public: + DeclarationParser(const Tokens& tokens, Symbol& symbol) + : _tokens(tokens), _symbol(symbol) {} + + // Returns false when the declaration does not have the expected shape. + bool parse() { + parsePrefix(); + if (_intro.empty()) { + return false; + } + + if (_intro == "init") { + if (peekPunct('?')) { + _symbol.isFailable = true; + _pos++; + } else if (peekPunct('!')) { + _symbol.isFailable = true; + _symbol.isImplicitlyUnwrappedFailable = true; + _pos++; + } + } else if (_intro != "subscript" && _intro != "deinit") { + skipSpaces(); + if (!atEnd() && _tokens[_pos].isFragment("identifier")) { + _pos++; + } + } + + skipSpaces(); + if (peekPunct('<')) { + skipBalanced(); + } + + bool isCallable = _intro == "func" || _intro == "init" || + _intro == "subscript" || _intro == "case" || + _intro == "macro"; + if (isCallable) { + skipSpaces(); + if (peekPunct('(')) { + if (!parseParameterList()) { + return false; + } + } else if (_intro != "case") { + return false; + } + parseEffects(); + skipSpaces(); + if (!atEnd() && _tokens[_pos].type == Token::Type::Arrow) { + _pos++; + size_t start = _pos; + size_t end = findTypeEnd(start); + _symbol.returnType = + makeTypeRef(_tokens.begin() + start, _tokens.begin() + end); + _pos = end; + } + if (_intro == "subscript") { + _symbol.valueType = _symbol.returnType; + parseAccessors(/*storedIfMissing*/ false); + } + return true; + } + + if (_intro == "var" || _intro == "let") { + skipSpaces(); + if (!peekPunct(':')) { + return false; + } + _pos++; + size_t start = _pos; + size_t end = findTypeEnd(start); + _symbol.valueType = + makeTypeRef(_tokens.begin() + start, _tokens.begin() + end); + _pos = end; + _symbol.isLet = _intro == "let"; + parseAccessors(/*storedIfMissing*/ !_symbol.isLet); + return true; + } + + if (_intro == "typealias") { + skipSpaces(); + if (peekPunct('=')) { + _pos++; + size_t start = _pos; + size_t end = findTypeEnd(start); + _symbol.aliasedType = + makeTypeRef(_tokens.begin() + start, _tokens.begin() + end); + } + return true; + } + + return true; + } + + const std::string& intro() const { return _intro; } + bool malformed() const { return _malformed; } + + private: + bool atEnd() const { return _pos >= _tokens.size(); } + + bool peekPunct(char c) const { return !atEnd() && _tokens[_pos].isPunct(c); } + + void skipSpaces() { + while (!atEnd() && _tokens[_pos].type == Token::Type::Space) { + _pos++; + } + } + + // Returns the attribute at `index` together with an argument list that + // follows it directly (`@attached(peer, names: ...)`), advancing `index` + // past both. + std::string consumeAttribute(size_t& index, size_t end) const { + llvm::StringRef text = _tokens[index].text; + std::string attribute = text.trim().str(); + index++; + // "@autoclosure " carries its separator inside the fragment; a following + // '(' then starts the attributed type, not an argument list. + bool abuts = !text.empty() && !llvm::isSpace(text.back()); + if (abuts && index < end && + (_tokens[index].isPunct('(') || _tokens[index].isPunct('<'))) { + int depth = 0; + while (index < end) { + const Token& token = _tokens[index++]; + attribute += token.text; + if (opens(token)) { + depth++; + } else if (closes(token) && --depth == 0) { + break; + } + } + } + return attribute; + } + + void skipBalanced() { + int depth = 0; + while (!atEnd()) { + const Token& token = _tokens[_pos++]; + if (opens(token)) { + depth++; + } else if (closes(token) && --depth == 0) { + return; + } + } + } + + bool isIntroKeyword(const Token& token) const { + static const std::set intros = { + "func", "init", "deinit", "subscript", "case", + "var", "let", "typealias", "associatedtype", "struct", + "enum", "protocol", "actor", "extension", "macro"}; + if (!token.isFragment("keyword")) { + return false; + } + if (token.text == "class") { + // `class func` / `class var` use `class` as a modifier. + return _symbol.kind == SymbolKind::Class || + _symbol.kind == SymbolKind::Actor; + } + return intros.count(token.text) > 0; + } + + void parsePrefix() { + while (!atEnd()) { + const Token& token = _tokens[_pos]; + if (token.isFragment("attribute")) { + _symbol.attributes.push_back(consumeAttribute(_pos, _tokens.size())); + continue; + } else if (isIntroKeyword(token)) { + _intro = token.text; + _pos++; + return; + } else if (token.isFragment("keyword")) { + _symbol.modifiers.push_back(token.text); + } else if (token.type != Token::Type::Space) { + return; + } + _pos++; + } + } + + // End of a type that starts at `start`: the first `where`, `{`, or `=` at + // nesting depth zero, or the end of the declaration. + size_t findTypeEnd(size_t start) const { + int depth = 0; + for (size_t i = start; i < _tokens.size(); i++) { + const Token& token = _tokens[i]; + if (opens(token)) { + depth++; + } else if (closes(token)) { + depth--; + } else if (depth == 0 && (token.isKeyword("where") || + token.isPunct('{') || token.isPunct('='))) { + return i; + } + } + return _tokens.size(); + } + + bool parseParameterList() { + _pos++; // '(' + std::vector> segments; + size_t segmentStart = _pos; + int depth = 0; + while (!atEnd()) { + const Token& token = _tokens[_pos]; + if (depth == 0 && (token.isPunct(',') || token.isPunct(')'))) { + segments.emplace_back(segmentStart, _pos); + segmentStart = _pos + 1; + if (token.isPunct(')')) { + _pos++; + for (const auto& segment : segments) { + parseParameter(segment.first, segment.second); + } + return true; + } + } else if (opens(token)) { + depth++; + } else if (closes(token)) { + depth--; + } + _pos++; + } + return false; + } + + void parseParameter(size_t begin, size_t end) { + while (begin < end && _tokens[begin].type == Token::Type::Space) { + begin++; + } + if (begin == end) { + return; + } + + Parameter parameter; + // Parameter attributes (result builders, property wrappers) precede the + // argument label: `@ViewBuilder content: () -> Content`. + while (begin < end && (_tokens[begin].isFragment("attribute") || + _tokens[begin].type == Token::Type::Space)) { + if (_tokens[begin].type == Token::Type::Space) { + begin++; + } else { + parameter.attributes.push_back(consumeAttribute(begin, end)); + } + } + bool hasExternal = false; + if (begin < end && _tokens[begin].isFragment("externalParam")) { + hasExternal = true; + parameter.label = _tokens[begin].text == "_" ? "" : _tokens[begin].text; + parameter.internalName = parameter.label; + begin++; + } + while (begin < end && _tokens[begin].type == Token::Type::Space) { + begin++; + } + if (begin < end && _tokens[begin].isFragment("internalParam")) { + parameter.internalName = _tokens[begin].text; + begin++; + } + while (begin < end && _tokens[begin].type == Token::Type::Space) { + begin++; + } + if (begin < end && _tokens[begin].isPunct(':')) { + begin++; + } else if (hasExternal) { + // An externalParam must be followed by a type annotation. + _malformed = true; + } + + // Default value: everything after a depth-zero '='. + size_t typeEnd = end; + int depth = 0; + for (size_t i = begin; i < end; i++) { + if (opens(_tokens[i])) { + depth++; + } else if (closes(_tokens[i])) { + depth--; + } else if (depth == 0 && _tokens[i].isPunct('=')) { + typeEnd = i; + parameter.defaultValue = + makeTypeRef(_tokens.begin() + i + 1, _tokens.begin() + end) + .spelling; + break; + } + } + + static const std::set modifiers = { + "inout", "borrowing", "consuming", "sending", "__owned", "__shared"}; + while (begin < typeEnd) { + const Token& token = _tokens[begin]; + if (token.type == Token::Type::Space) { + begin++; + } else if (token.isFragment("attribute")) { + parameter.attributes.push_back(consumeAttribute(begin, typeEnd)); + } else if (token.isFragment("keyword") && modifiers.count(token.text)) { + parameter.modifier = token.text; + begin++; + } else { + break; + } + } + + size_t last = typeEnd; + while (last > begin && _tokens[last - 1].type == Token::Type::Space) { + last--; + } + if (last > begin && _tokens[last - 1].type == Token::Type::Word && + _tokens[last - 1].text == "...") { + parameter.isVariadic = true; + last--; + } + + parameter.type = + makeTypeRef(_tokens.begin() + begin, _tokens.begin() + last); + _symbol.parameters.push_back(std::move(parameter)); + } + + void parseEffects() { + while (true) { + skipSpaces(); + if (atEnd()) { + return; + } + const Token& token = _tokens[_pos]; + if (token.isKeyword("async") || token.isKeyword("reasync")) { + _symbol.isAsync = true; + _pos++; + } else if (token.isKeyword("throws")) { + _symbol.isThrowing = true; + _pos++; + if (peekPunct('(')) { + size_t start = _pos + 1; + skipBalanced(); + _symbol.thrownType = + makeTypeRef(_tokens.begin() + start, _tokens.begin() + _pos - 1); + } + } else if (token.isKeyword("rethrows")) { + _symbol.isThrowing = true; + _symbol.isRethrowing = true; + _pos++; + } else { + return; + } + } + } + + // `{ get }`, `{ get set }`, or no accessor block. A `var` without an + // accessor block is stored and therefore settable. + void parseAccessors(bool storedIfMissing) { + skipSpaces(); + if (!peekPunct('{')) { + _symbol.isSettable = storedIfMissing; + return; + } + while (!atEnd() && !_tokens[_pos].isPunct('}')) { + const Token& token = _tokens[_pos]; + if (token.isKeyword("set")) { + _symbol.isSettable = true; + } else if (token.isKeyword("async")) { + _symbol.isAsync = true; + } else if (token.isKeyword("throws")) { + _symbol.isThrowing = true; + } + _pos++; + } + } + + const Tokens& _tokens; + Symbol& _symbol; + size_t _pos = 0; + std::string _intro; + bool _malformed = false; +}; + +// "scale(by:)" -> {"by"}, "describe(_:)" -> {""}, "x" -> none. +std::optional> labelsFromName(llvm::StringRef name) { + size_t open = name.find('('); + if (open == llvm::StringRef::npos || !name.endswith(")")) { + return std::nullopt; + } + llvm::StringRef inner = name.slice(open + 1, name.size() - 1); + std::vector labels; + while (!inner.empty()) { + auto split = inner.split(':'); + labels.push_back(split.first == "_" ? "" : split.first.str()); + inner = split.second; + } + return labels; +} + +SymbolKind kindFromIdentifier(llvm::StringRef identifier) { + return llvm::StringSwitch(identifier) + .Case("swift.class", SymbolKind::Class) + .Case("swift.struct", SymbolKind::Struct) + .Case("swift.enum", SymbolKind::Enum) + .Case("swift.protocol", SymbolKind::Protocol) + .Case("swift.enum.case", SymbolKind::EnumCase) + .Case("swift.init", SymbolKind::Initializer) + .Case("swift.deinit", SymbolKind::Deinitializer) + .Case("swift.method", SymbolKind::InstanceMethod) + .Case("swift.type.method", SymbolKind::TypeMethod) + .Case("swift.func.op", SymbolKind::Operator) + .Case("swift.property", SymbolKind::InstanceProperty) + .Case("swift.type.property", SymbolKind::TypeProperty) + .Case("swift.subscript", SymbolKind::InstanceSubscript) + .Case("swift.type.subscript", SymbolKind::TypeSubscript) + .Case("swift.func", SymbolKind::Function) + .Case("swift.var", SymbolKind::Variable) + .Case("swift.typealias", SymbolKind::TypeAlias) + .Case("swift.associatedtype", SymbolKind::AssociatedType) + .Case("swift.macro", SymbolKind::Macro) + .Case("swift.extension", SymbolKind::Extension) + .Default(SymbolKind::Unknown); +} + +AccessLevel accessFromString(llvm::StringRef access) { + return llvm::StringSwitch(access) + .Case("private", AccessLevel::Private) + .Case("fileprivate", AccessLevel::FilePrivate) + .Case("internal", AccessLevel::Internal) + .Case("package", AccessLevel::Package) + .Case("public", AccessLevel::Public) + .Case("open", AccessLevel::Open) + .Default(AccessLevel::Unknown); +} + +Fragments parseFragments(const Array* array) { + Fragments fragments; + if (!array) { + return fragments; + } + for (const auto& value : *array) { + const Object* object = value.getAsObject(); + if (!object) { + continue; + } + fragments.push_back(Fragment{str(object, "kind"), str(object, "spelling"), + str(object, "preciseIdentifier")}); + } + return fragments; +} + +std::vector parseConstraints(const Array* array) { + std::vector constraints; + if (!array) { + return constraints; + } + for (const auto& value : *array) { + const Object* object = value.getAsObject(); + if (!object) { + continue; + } + constraints.push_back( + GenericConstraint{str(object, "kind"), str(object, "lhs"), + str(object, "rhs"), str(object, "rhsPrecise")}); + } + return constraints; +} + +void parseAvailability(const Array* array, Symbol& symbol) { + if (!array) { + return; + } + for (const auto& value : *array) { + const Object* object = value.getAsObject(); + if (!object) { + continue; + } + Availability availability; + availability.domain = str(object, "domain"); + availability.introduced = version(object->getObject("introduced")); + availability.deprecated = version(object->getObject("deprecated")); + availability.obsoleted = version(object->getObject("obsoleted")); + availability.message = str(object, "message"); + availability.renamed = str(object, "renamed"); + availability.isUnconditionallyDeprecated = + boolean(object, "isUnconditionallyDeprecated"); + availability.isUnconditionallyUnavailable = + boolean(object, "isUnconditionallyUnavailable"); + symbol.availability.push_back(std::move(availability)); + } +} + +std::optional parseSymbol(const Object& object, + const std::string& graphName, + std::vector& diagnostics) { + Symbol symbol; + symbol.usr = str(object.getObject("identifier"), "precise"); + symbol.preciseId = symbol.usr; + if (symbol.preciseId.empty()) { + report(diagnostics, Severity::Warning, "missing-field", + "symbol without identifier.precise skipped", graphName); + return std::nullopt; + } + + symbol.kindIdentifier = str(object.getObject("kind"), "identifier"); + symbol.kind = kindFromIdentifier(symbol.kindIdentifier); + if (symbol.kind == SymbolKind::Unknown) { + report(diagnostics, Severity::Warning, "unknown-symbol-kind", + "unrecognized symbol kind '" + symbol.kindIdentifier + "'", + graphName, symbol.preciseId); + } + + if (const Array* components = object.getArray("pathComponents")) { + for (const auto& component : *components) { + if (auto value = component.getAsString()) { + symbol.pathComponents.push_back(value->str()); + } + } + } + symbol.name = symbol.pathComponents.empty() + ? str(object.getObject("names"), "title") + : symbol.pathComponents.back(); + symbol.baseName = llvm::StringRef(symbol.name).split('(').first.str(); + symbol.access = accessFromString(str(&object, "accessLevel")); + symbol.isSynthesized = + llvm::StringRef(symbol.preciseId).contains("::SYNTHESIZED::"); + symbol.sourceGraph = graphName; + + symbol.declaration = parseFragments(object.getArray("declarationFragments")); + for (const auto& fragment : symbol.declaration) { + symbol.declarationText += fragment.spelling; + } + + if (const Object* generics = object.getObject("swiftGenerics")) { + if (const Array* parameters = generics->getArray("parameters")) { + for (const auto& value : *parameters) { + if (const Object* parameter = value.getAsObject()) { + symbol.genericParameters.push_back(GenericParameter{ + str(parameter, "name"), integer(parameter, "depth"), + integer(parameter, "index")}); + } + } + } + symbol.genericConstraints = + parseConstraints(generics->getArray("constraints")); + } + + if (const Object* extension = object.getObject("swiftExtension")) { + symbol.extension = SwiftExtensionInfo{ + str(extension, "extendedModule"), str(extension, "typeKind"), + parseConstraints(extension->getArray("constraints"))}; + } + + parseAvailability(object.getArray("availability"), symbol); + + if (const Object* doc = object.getObject("docComment")) { + if (const Array* lines = doc->getArray("lines")) { + for (const auto& line : *lines) { + if (!symbol.docComment.empty()) { + symbol.docComment += '\n'; + } + symbol.docComment += str(line.getAsObject(), "text"); + } + } + } + + if (const Object* location = object.getObject("location")) { + const Object* position = location->getObject("position"); + symbol.location = + SourceLocation{str(location, "uri"), integer(position, "line"), + integer(position, "character")}; + } + + Tokens tokens = tokenize(symbol.declaration); + DeclarationParser parser(tokens, symbol); + bool parsed = parser.parse(); + if (parser.intro() == "actor") { + symbol.kind = SymbolKind::Actor; + } + if (!parsed || parser.malformed()) { + report(diagnostics, Severity::Warning, "unparsed-declaration", + "could not parse declaration '" + symbol.declarationText + "'", + graphName, symbol.preciseId); + } + + // The functionSignature return is cleaner than the declaration tail (no + // trailing where-clause) and is present for every function-like symbol. + if (const Object* signature = object.getObject("functionSignature")) { + if (const Array* returns = signature->getArray("returns")) { + Fragments fragments = parseFragments(returns); + Tokens returnTokens = tokenize(fragments); + TypeRef type = makeTypeRef(returnTokens.begin(), returnTokens.end()); + if (isVoid(type) || type.empty()) { + symbol.returnType.reset(); + } else { + symbol.returnType = type; + } + } + } + if (symbol.returnType && isVoid(*symbol.returnType)) { + symbol.returnType.reset(); + } + if (symbol.kind == SymbolKind::InstanceSubscript || + symbol.kind == SymbolKind::TypeSubscript) { + symbol.valueType = symbol.returnType; + } + + if (auto labels = labelsFromName(symbol.name)) { + bool matches = labels->size() == symbol.parameters.size(); + for (size_t i = 0; matches && i < labels->size(); i++) { + matches = (*labels)[i] == symbol.parameters[i].label; + } + if (!matches) { + report(diagnostics, Severity::Warning, "parameter-label-mismatch", + "parsed parameters of '" + symbol.declarationText + + "' do not match the symbol name '" + symbol.name + "'", + graphName, symbol.preciseId); + } + } + + switch (symbol.kind) { + case SymbolKind::TypeMethod: + case SymbolKind::TypeProperty: + case SymbolKind::TypeSubscript: + symbol.isStatic = true; + break; + case SymbolKind::Operator: + symbol.isStatic = std::count(symbol.modifiers.begin(), + symbol.modifiers.end(), "static") > 0; + break; + default: + break; + } + + return symbol; +} + +// Members and top-level declarations are listed in source order; synthesized +// symbols have no location and follow, ordered by USR. +void sortBySourceOrder(std::vector& ids, const Module& module) { + auto key = [&](const std::string& id) { + const Symbol* symbol = module.find(id); + if (!symbol || !symbol->location) { + return std::make_tuple(1, std::string(), 0, 0, id); + } + return std::make_tuple(0, symbol->location->uri, symbol->location->line, + symbol->location->character, id); + }; + std::sort(ids.begin(), ids.end(), + [&](const std::string& a, const std::string& b) { + return key(a) < key(b); + }); + ids.erase(std::unique(ids.begin(), ids.end()), ids.end()); +} + +void resolve(Module& module, std::vector& diagnostics) { + std::sort(module.relationships.begin(), module.relationships.end(), + [](const Relationship& a, const Relationship& b) { + return std::tie(a.kind, a.source, a.target) < + std::tie(b.kind, b.source, b.target); + }); + module.relationships.erase( + std::unique(module.relationships.begin(), module.relationships.end(), + [](const Relationship& a, const Relationship& b) { + return std::tie(a.kind, a.source, a.target) == + std::tie(b.kind, b.source, b.target); + }), + module.relationships.end()); + + auto rememberExternal = [&](const Relationship& relationship) { + if (!module.find(relationship.target)) { + module.externalNames[relationship.target] = + relationship.targetFallback.empty() ? relationship.target + : relationship.targetFallback; + } + }; + + for (const auto& relationship : module.relationships) { + const std::string& kind = relationship.kind; + + // A relationship names a USR, which every variant keyed by it shares + // (see insertSymbol). Membership applies only to the variant declared + // in the target type. + std::vector sources; + const Symbol* target = module.find(relationship.target); + bool isMembership = kind == "memberOf" || kind == "requirementOf" || + kind == "optionalRequirementOf"; + for (auto it = module.symbols.lower_bound(relationship.source); + it != module.symbols.end() && + llvm::StringRef(it->first).startswith(relationship.source); + ++it) { + Symbol& candidate = it->second; + if (candidate.usr != relationship.source) { + continue; + } + if (isMembership && target && !candidate.pathComponents.empty() && + !std::equal(target->pathComponents.begin(), + target->pathComponents.end(), + candidate.pathComponents.begin(), + candidate.pathComponents.end() - 1)) { + continue; + } + sources.push_back(&candidate); + } + + if (sources.empty()) { + // Conformances this module's extensions add to external types + // (`extension Array: DataProtocol where Element == UInt8`). + if (kind == "conformsTo" || kind == "inheritsFrom") { + ExternalType& external = module.externalTypes[relationship.source]; + external.preciseId = relationship.source; + external.conformances.push_back(relationship.target); + rememberExternal(relationship); + continue; + } + report(diagnostics, Severity::Warning, "dangling-relationship", + kind + " relationship from unknown symbol '" + + relationship.source + "'", + module.name, relationship.source); + continue; + } + + for (Symbol* sourcePtr : sources) { + Symbol& source = *sourcePtr; + if (kind == "memberOf" || kind == "requirementOf" || + kind == "optionalRequirementOf") { + source.parentId = relationship.target; + if (!relationship.sourceOriginId.empty()) { + source.sourceOriginId = relationship.sourceOriginId; + source.sourceOriginName = relationship.sourceOriginName; + } + if (kind != "memberOf") { + source.isProtocolRequirement = true; + source.isOptionalRequirement = kind == "optionalRequirementOf"; + } + + auto targetIt = module.symbols.find(relationship.target); + if (targetIt != module.symbols.end()) { + targetIt->second.memberIds.push_back(source.preciseId); + continue; + } + rememberExternal(relationship); + ExternalType& external = module.externalTypes[relationship.target]; + external.preciseId = relationship.target; + if (source.extension) { + external.extendedModule = source.extension->extendedModule; + external.typeKind = source.extension->typeKind; + } + external.memberIds.push_back(source.preciseId); + } else if (kind == "conformsTo") { + source.conformances.push_back(relationship.target); + rememberExternal(relationship); + } else if (kind == "inheritsFrom") { + if (source.kind == SymbolKind::Protocol) { + source.conformances.push_back(relationship.target); + } else { + source.superclassId = relationship.target; + } + rememberExternal(relationship); + } else if (kind == "overrides") { + source.overriddenId = relationship.target; + rememberExternal(relationship); + } else if (kind == "defaultImplementationOf") { + source.defaultImplementationOf.push_back(relationship.target); + rememberExternal(relationship); + } + } + } + + for (auto& entry : module.symbols) { + Symbol& symbol = entry.second; + sortBySourceOrder(symbol.memberIds, module); + std::sort(symbol.conformances.begin(), symbol.conformances.end()); + symbol.conformances.erase( + std::unique(symbol.conformances.begin(), symbol.conformances.end()), + symbol.conformances.end()); + std::sort(symbol.defaultImplementationOf.begin(), + symbol.defaultImplementationOf.end()); + if (symbol.parentId.empty()) { + module.topLevelIds.push_back(symbol.preciseId); + } + } + for (auto& entry : module.externalTypes) { + ExternalType& external = entry.second; + sortBySourceOrder(external.memberIds, module); + std::sort(external.conformances.begin(), external.conformances.end()); + external.conformances.erase( + std::unique(external.conformances.begin(), external.conformances.end()), + external.conformances.end()); + // Graphs name a relationship's target, never its source; an extended + // type's name is only known when some relationship targets it. + auto name = module.externalNames.find(external.preciseId); + external.qualifiedName = + name != module.externalNames.end() ? name->second : external.preciseId; + } + sortBySourceOrder(module.topLevelIds, module); + std::sort(module.graphFiles.begin(), module.graphFiles.end()); +} + +// Structural scan of JSON text that locates object members and array +// elements without building a DOM. Whole SDK graphs run to hundreds of MB, and +// an llvm::json DOM of one costs tens of GB, so the loader skims the top level +// and parses each symbol and relationship on its own. +namespace JsonSkimmer { + +size_t skipSpace(llvm::StringRef text, size_t i) { + while (i < text.size() && llvm::isSpace(text[i])) { + i++; + } + return i; +} + +// Index one past the value starting at `i`, or npos. +size_t skipValue(llvm::StringRef text, size_t i) { + if (i >= text.size()) { + return llvm::StringRef::npos; + } + char c = text[i]; + if (c == '"') { + for (i++; i < text.size(); i++) { + if (text[i] == '\\') { + i++; + } else if (text[i] == '"') { + return i + 1; + } + } + return llvm::StringRef::npos; + } + if (c == '{' || c == '[') { + int depth = 0; + for (; i < text.size(); i++) { + char d = text[i]; + if (d == '"') { + size_t end = skipValue(text, i); + if (end == llvm::StringRef::npos) { + return end; + } + i = end - 1; + } else if (d == '{' || d == '[') { + depth++; + } else if ((d == '}' || d == ']') && --depth == 0) { + return i + 1; + } + } + return llvm::StringRef::npos; + } + size_t start = i; + while (i < text.size() && !llvm::isSpace(text[i]) && + !llvm::StringRef(",}]").contains(text[i])) { + i++; + } + return i == start ? llvm::StringRef::npos : i; +} + +bool fail(std::string& error, const char* what, size_t offset) { + error = std::string(what) + " at offset " + std::to_string(offset); + return false; +} + +bool objectMembers( + llvm::StringRef text, + std::vector>& members, + std::string& error) { + size_t i = skipSpace(text, 0); + if (i >= text.size() || text[i] != '{') { + return fail(error, "expected '{'", i); + } + i = skipSpace(text, i + 1); + if (i < text.size() && text[i] == '}') { + i++; + } else { + while (true) { + i = skipSpace(text, i); + size_t keyEnd = skipValue(text, i); + if (i >= text.size() || text[i] != '"' || + keyEnd == llvm::StringRef::npos) { + return fail(error, "expected member name", i); + } + llvm::StringRef key = text.slice(i + 1, keyEnd - 1); + i = skipSpace(text, keyEnd); + if (i >= text.size() || text[i] != ':') { + return fail(error, "expected ':'", i); + } + i = skipSpace(text, i + 1); + size_t valueEnd = skipValue(text, i); + if (valueEnd == llvm::StringRef::npos) { + return fail(error, "malformed value", i); + } + members.emplace_back(key, text.slice(i, valueEnd)); + i = skipSpace(text, valueEnd); + if (i < text.size() && text[i] == ',') { + i++; + continue; + } + if (i < text.size() && text[i] == '}') { + i++; + break; + } + return fail(error, "expected ',' or '}'", i); + } + } + if (skipSpace(text, i) != text.size()) { + return fail(error, "trailing content", i); + } + return true; +} + +bool arrayElements(llvm::StringRef text, + llvm::function_ref visit, + std::string& error) { + size_t i = skipSpace(text, 0); + if (i >= text.size() || text[i] != '[') { + return fail(error, "expected '['", i); + } + i = skipSpace(text, i + 1); + if (i < text.size() && text[i] == ']') { + return true; + } + while (true) { + i = skipSpace(text, i); + size_t end = skipValue(text, i); + if (end == llvm::StringRef::npos) { + return fail(error, "malformed element", i); + } + visit(text.slice(i, end)); + i = skipSpace(text, end); + if (i < text.size() && text[i] == ',') { + i++; + continue; + } + if (i < text.size() && text[i] == ']') { + return true; + } + return fail(error, "expected ',' or ']'", i); + } +} + +} // namespace JsonSkimmer + +} // namespace + +std::vector SymbolGraphLoader::findGraphFiles( + const std::string& directory, std::vector& diagnostics) { + std::vector files; + if (!fs::is_directory(directory)) { + report(diagnostics, Severity::Error, "missing-directory", + "symbol graph directory does not exist", directory); + return files; + } + + std::error_code ec; + for (fs::recursive_directory_iterator it(directory, ec), end; + it != end && !ec; it.increment(ec)) { + if (it->type() != fs::file_type::regular_file) { + continue; + } + if (isGraphFileName(path::filename(it->path()))) { + files.push_back(it->path()); + } + } + if (ec) { + report(diagnostics, Severity::Error, "unreadable-directory", ec.message(), + directory); + } + std::sort(files.begin(), files.end()); + return files; +} + +void SymbolGraphLoader::addFile(const std::string& filePath, + const std::string& displayName) { + auto buffer = llvm::MemoryBuffer::getFile(filePath); + if (!buffer) { + report(_diagnostics, Severity::Error, "unreadable-file", + buffer.getError().message(), displayName); + return; + } + addBuffer((*buffer)->getBuffer(), displayName); +} + +void SymbolGraphLoader::addBuffer(llvm::StringRef json, + const std::string& displayName) { + std::vector> members; + std::string error; + if (!JsonSkimmer::objectMembers(json, members, error)) { + report(_diagnostics, Severity::Error, "invalid-json", error, displayName); + return; + } + llvm::StringRef metadataText, moduleText, symbolsText, relationshipsText; + for (const auto& member : members) { + if (member.first == "metadata") { + metadataText = member.second; + } else if (member.first == "module") { + moduleText = member.second; + } else if (member.first == "symbols") { + symbolsText = member.second; + } else if (member.first == "relationships") { + relationshipsText = member.second; + } + } + + auto parseSection = + [&](llvm::StringRef text, + llvm::StringRef name) -> std::optional { + if (text.empty()) { + return std::nullopt; + } + auto value = llvm::json::parse(text); + if (!value) { + report(_diagnostics, Severity::Error, "invalid-json", + name.str() + ": " + llvm::toString(value.takeError()), + displayName); + return std::nullopt; + } + return std::move(*value); + }; + + auto metadataValue = parseSection(metadataText, "metadata"); + const Object* metadata = + metadataValue ? metadataValue->getAsObject() : nullptr; + auto format = + version(metadata ? metadata->getObject("formatVersion") : nullptr); + if (!format) { + report(_diagnostics, Severity::Error, "missing-field", + "metadata.formatVersion is missing", displayName); + return; + } + if (format->major != kSupportedFormatMajor) { + report(_diagnostics, Severity::Error, "unsupported-format-version", + "symbol graph format " + std::to_string(format->major) + "." + + std::to_string(format->minor) + " is not supported", + displayName); + return; + } + if (format->minor > kNewestKnownFormatMinor) { + report(_diagnostics, Severity::Warning, "newer-format-version", + "symbol graph format 0." + std::to_string(format->minor) + + " is newer than the newest validated format 0." + + std::to_string(kNewestKnownFormatMinor), + displayName); + } + + auto moduleValue = parseSection(moduleText, "module"); + const Object* moduleObject = + moduleValue ? moduleValue->getAsObject() : nullptr; + std::string moduleName = str(moduleObject, "name"); + if (moduleName.empty()) { + report(_diagnostics, Severity::Error, "missing-field", + "module.name is missing", displayName); + return; + } + + Module& module = _modules[moduleName]; + if (module.name.empty()) { + module.name = moduleName; + module.formatVersion = *format; + module.generator = str(metadata, "generator"); + if (const Object* platform = moduleObject->getObject("platform")) { + module.platform.architecture = str(platform, "architecture"); + module.platform.vendor = str(platform, "vendor"); + module.platform.environment = str(platform, "environment"); + if (const Object* os = platform->getObject("operatingSystem")) { + module.platform.operatingSystem = str(os, "name"); + module.platform.minimumVersion = + version(os->getObject("minimumVersion")); + } + } + } else if (std::tie(module.formatVersion.major, module.formatVersion.minor) != + std::tie(format->major, format->minor)) { + report(_diagnostics, Severity::Warning, "mixed-format-versions", + "graph files of module '" + moduleName + + "' use different format versions", + displayName); + } + module.graphFiles.push_back(displayName); + + // Elements are parsed one at a time; see JsonSkimmer. + auto forEachObject = [&](llvm::StringRef arrayText, llvm::StringRef name, + llvm::function_ref visit) { + if (arrayText.empty()) { + return; + } + std::string arrayError; + bool ok = JsonSkimmer::arrayElements( + arrayText, + [&](llvm::StringRef element) { + auto value = llvm::json::parse(element); + if (!value) { + report(_diagnostics, Severity::Error, "invalid-json", + name.str() + ": " + llvm::toString(value.takeError()), + displayName); + return; + } + if (const Object* object = value->getAsObject()) { + visit(*object); + } + }, + arrayError); + if (!ok) { + report(_diagnostics, Severity::Error, "invalid-json", + name.str() + ": " + arrayError, displayName); + } + }; + + // `@.symbols.json`: graphs of cross-import overlays + // carry the overlay's name only in the file name. + std::string declaringModule = llvm::StringRef(path::filename(displayName)) + .split('@') + .first.split('.') + .first.str(); + if (declaringModule == moduleName) { + declaringModule.clear(); + } + + forEachObject(symbolsText, "symbols", [&](const Object& object) { + auto symbol = parseSymbol(object, displayName, _diagnostics); + if (symbol) { + symbol->declaringModule = declaringModule; + insertSymbol(module, std::move(*symbol), displayName); + } + }); + + forEachObject(relationshipsText, "relationships", [&](const Object& object) { + const Object* origin = object.getObject("sourceOrigin"); + module.relationships.push_back( + Relationship{str(&object, "kind"), str(&object, "source"), + str(&object, "target"), str(&object, "targetFallback"), + str(origin, "identifier"), str(origin, "displayName")}); + }); +} + +void SymbolGraphLoader::insertSymbol(Module& module, Symbol symbol, + const std::string& displayName) { + auto existing = module.symbols.find(symbol.preciseId); + if (existing == module.symbols.end()) { + std::string id = symbol.preciseId; + module.symbols.emplace(std::move(id), std::move(symbol)); + return; + } + Symbol& other = existing->second; + if (other.declarationText == symbol.declarationText && + other.pathComponents == symbol.pathComponents) { + return; + } + auto ownerOf = [](const Symbol& s) { + return std::vector(s.pathComponents.begin(), + s.pathComponents.empty() + ? s.pathComponents.end() + : s.pathComponents.end() - 1); + }; + if (ownerOf(other) != ownerOf(symbol)) { + // An Objective-C method redeclared by a subclass (NSMutableArray's + // settable subscript) keeps the superclass method's USR. The variant + // whose path sorts first keeps the plain USR; others are keyed by owner. + if (symbol.pathComponents < other.pathComponents) { + std::swap(other, symbol); + } + symbol.preciseId = symbol.usr + "#" + llvm::join(ownerOf(symbol), "."); + if (!module.symbols.count(symbol.preciseId)) { + std::string id = symbol.preciseId; + module.symbols.emplace(std::move(id), std::move(symbol)); + } + return; + } + if (other.isAsync != symbol.isAsync) { + // Swift imports an Objective-C completion-handler method twice, as the + // original and as an `async` variant, under the same USR. Keep both; the + // original keeps the plain USR. + if (!symbol.isAsync) { + std::swap(other, symbol); + } + symbol.preciseId = symbol.usr + "#async"; + if (!module.symbols.count(symbol.preciseId)) { + std::string id = symbol.preciseId; + module.symbols.emplace(std::move(id), std::move(symbol)); + } + return; + } + report(_diagnostics, Severity::Warning, "duplicate-symbol", + "symbol declared differently in '" + other.sourceGraph + "' and '" + + displayName + "'; keeping the first", + displayName, symbol.preciseId); +} + +ModuleSet SymbolGraphLoader::finish() { + ModuleSet result; + for (auto& entry : _modules) { + resolve(entry.second, _diagnostics); + } + result.modules = std::move(_modules); + result.diagnostics = std::move(_diagnostics); + return result; +} + +ModuleSet loadSymbolGraphDirectory(const std::string& directory) { + std::vector diagnostics; + auto files = SymbolGraphLoader::findGraphFiles(directory, diagnostics); + + SymbolGraphLoader loader; + for (const auto& file : files) { + llvm::StringRef relative = file; + relative.consume_front(directory); + relative = relative.ltrim('/'); + loader.addFile(file, relative.str()); + } + ModuleSet result = loader.finish(); + result.diagnostics.insert(result.diagnostics.begin(), diagnostics.begin(), + diagnostics.end()); + return result; +} + +} // namespace Swift diff --git a/metadata-generator/src/Swift/SymbolGraphLoader.h b/metadata-generator/src/Swift/SymbolGraphLoader.h new file mode 100644 index 000000000..75d21607d --- /dev/null +++ b/metadata-generator/src/Swift/SymbolGraphLoader.h @@ -0,0 +1,50 @@ +#pragma once + +#include + +#include +#include + +#include "SwiftIR.h" + +namespace Swift { + +// Reads Swift symbol graph files (`swiftc -emit-symbol-graph` / +// `swift symbolgraph-extract`) into the Swift IR. +// +// A module's declarations can span several graph files: `M.symbols.json` +// holds M's own declarations, `M@Other.symbols.json` holds M's extensions of +// types declared in module Other. Files are grouped by the module name inside +// the graph, not by file name. +class SymbolGraphLoader { + public: + // Newest symbol graph format this loader has been validated against. + // Newer minor versions load with a warning; other major versions are + // rejected. + static constexpr int kSupportedFormatMajor = 0; + static constexpr int kNewestKnownFormatMinor = 6; + + // Graph files under `directory` (recursive), sorted for deterministic + // loading. + static std::vector findGraphFiles( + const std::string& directory, std::vector& diagnostics); + + void addFile(const std::string& path, const std::string& displayName); + void addBuffer(llvm::StringRef json, const std::string& displayName); + + // Resolves relationships across all added graphs. The loader is spent + // afterwards. + ModuleSet finish(); + + private: + void insertSymbol(Module& module, Symbol symbol, + const std::string& displayName); + + std::map _modules; + std::vector _diagnostics; +}; + +// Convenience: find, load and resolve every graph under `directory`. +ModuleSet loadSymbolGraphDirectory(const std::string& directory); + +} // namespace Swift diff --git a/metadata-generator/src/Swift/ThunkEmitter.cpp b/metadata-generator/src/Swift/ThunkEmitter.cpp new file mode 100644 index 000000000..fe6d8f0b8 --- /dev/null +++ b/metadata-generator/src/Swift/ThunkEmitter.cpp @@ -0,0 +1,609 @@ +#include "ThunkEmitter.h" + +#include + +#include +#include +#include + +#include "SwiftSource.h" +#include "SwiftSurface.h" + +namespace Swift { + +namespace { + +// Byte offsets of the API table slots used at registration. +constexpr int kRegisterModuleSlot = 10 * 8; +constexpr int kRegisterTypeSlot = 11 * 8; +constexpr int kRegisterMemberSlot = 12 * 8; + +std::string quoted(const std::string& text) { + std::string out = "\""; + for (char c : text) { + if (c == '"' || c == '\\') { + out += '\\'; + } + out += c; + } + return out + "\""; +} + +class Emitter { + public: + Emitter(const Module& module, const Classification& classification) + : _module(module), + _classification(classification), + _surface(describeSurface(module, classification)) {} + + ThunkSource run() { + ThunkSource result; + result.registerSymbol = "ns_swift_register_" + _module.name; + + std::string thunks; + for (const auto& member : _surface.members) { + thunks += emitMember(member); + } + + result.fingerprint = fingerprint(_registrations); + result.thunkCount = _thunkCount; + result.source = header() + support() + enumHelpers() + typeIndexFunction() + + thunks + registration(result); + return result; + } + + private: + int typeIndexOf(const std::string& id) const { return _surface.indexOf(id); } + + std::string typeName(const std::string& id) const { + const Symbol* symbol = _module.find(id); + return symbol ? qualifiedTypeName(_module, *symbol) : ""; + } + + // Swift expression reading slot `slot` as the non-optional value of + // `type`, for conversions that cannot fail. + std::string primitiveRead(const BridgedType& type, int slot) const { + std::string index = std::to_string(slot); + switch (type.bridge) { + case Bridge::Bool: + return "rt.bool(" + index + ")"; + case Bridge::Integer: { + const IntegerWidth* info = integerWidth(type); + std::string swiftType = info ? info->swiftType : "Int"; + bool isSigned = !info || info->isSigned; + std::string raw = + isSigned ? "rt.int64(" + index + ")" : "rt.uint64(" + index + ")"; + if (swiftType == "Int64" || swiftType == "UInt64") { + return raw; + } + // The runtime has range-checked the value against the width. + return swiftType + "(truncatingIfNeeded: " + raw + ")"; + } + case Bridge::Floating: { + const std::string& usr = unwrappedNode(type).usr(); + if (usr == KnownTypes::kFloat) { + return "Float(rt.double(" + index + "))"; + } + if (usr == KnownTypes::kCGFloat) { + return "CGFloat(rt.double(" + index + "))"; + } + return "rt.double(" + index + ")"; + } + case Bridge::String: + return "rt.string(" + index + ")"; + default: + return ""; + } + } + + // Lines binding `name` to argument `slot`; `label` describes it in errors. + std::string readArgument(const BridgedType& type, int slot, + const std::string& name, + const std::string& label) const { + std::string index = std::to_string(slot); + std::string cast; + std::string expected; + switch (type.bridge) { + case Bridge::ClassHandle: + cast = "rt.object(" + index + ") as? " + typeName(type.symbolId); + expected = typeName(type.symbolId); + break; + case Bridge::StructBox: + cast = "(rt.object(" + index + ") as? __NSBox<" + + typeName(type.symbolId) + ">)?.value"; + expected = typeName(type.symbolId); + break; + case Bridge::EnumCase: + cast = "__nsEnum" + std::to_string(typeIndexOf(type.symbolId)) + + "(rt.string(" + index + "))"; + expected = "a case of " + typeName(type.symbolId); + break; + default: { + std::string read = primitiveRead(type, slot); + if (type.optional) { + return " let " + name + " = rt.isNull(" + index + + ") ? nil : " + read + "\n"; + } + return " let " + name + " = " + read + "\n"; + } + } + std::string failure = "return rt.throwTypeError(" + + quoted(label + " must be " + expected) + ")"; + if (!type.optional) { + return " guard let " + name + " = " + cast + " else { " + failure + + " }\n"; + } + return " var " + name + ": " + valueTypeName(type) + "? = nil\n" + + " if !rt.isNull(" + index + ") {\n" + + " guard let value = " + cast + " else { " + failure + " }\n" + + " " + name + " = value\n" + " }\n"; + } + + std::string valueTypeName(const BridgedType& type) const { + if (!type.symbolId.empty()) { + return typeName(type.symbolId); + } + return swiftTypeText(unwrappedNode(type), _module); + } + + // Statements returning `value` (a non-optional expression of `type`). + std::string returnValue(const BridgedType& type, + const std::string& value) const { + switch (type.bridge) { + case Bridge::Void: + return "rt.returnVoid()"; + case Bridge::Bool: + return "rt.returnBool(" + value + ")"; + case Bridge::Integer: { + const IntegerWidth* info = integerWidth(type); + if (info && !info->isSigned) { + return "rt.returnUInt64(UInt64(" + value + "))"; + } + return "rt.returnInt64(Int64(" + value + "))"; + } + case Bridge::Floating: + return "rt.returnDouble(Double(" + value + "))"; + case Bridge::String: + return "rt.returnString(" + value + ")"; + case Bridge::ClassHandle: + return "rt.returnObject(" + value + ", __nsTypeIndex(" + value + ", " + + std::to_string(typeIndexOf(type.symbolId)) + "))"; + case Bridge::StructBox: + return "rt.returnObject(__NSBox(" + value + "), " + + std::to_string(typeIndexOf(type.symbolId)) + ")"; + case Bridge::EnumCase: + return "rt.returnString(__nsEnumName" + + std::to_string(typeIndexOf(type.symbolId)) + "(" + value + "))"; + case Bridge::None: + return "rt.returnVoid()"; + } + return "rt.returnVoid()"; + } + + std::string returnResult(const BridgedType& type, + const std::string& indent) const { + if (type.optional) { + return indent + "if let result {\n" + indent + " " + + returnValue(type, "result") + "\n" + indent + "} else {\n" + + indent + " rt.returnNull()\n" + indent + "}\n"; + } + return indent + returnValue(type, "result") + "\n"; + } + + // Receiver binding for instance members; returns the receiver expression. + std::string bindReceiver(const Symbol& owner, std::string& body) const { + std::string type = qualifiedTypeName(_module, owner); + std::string failure = + "return rt.throwTypeError(" + quoted("receiver must be " + type) + ")"; + if (owner.kind == SymbolKind::Struct) { + body += " guard let box = rt.object(0) as? __NSBox<" + type + + "> else { " + failure + " }\n"; + // Mutating members and setters change the boxed copy in place. + return "box.value"; + } + if (owner.kind == SymbolKind::Enum) { + body += " guard let receiver = __nsEnum" + + std::to_string(typeIndexOf(owner.preciseId)) + + "(rt.string(0)) else { " + failure + " }\n"; + return "receiver"; + } + body += " guard let receiver = rt.object(0) as? " + type + " else { " + + failure + " }\n"; + return "receiver"; + } + + std::string thunkHeader(int index) const { + return "private func __nsThunk" + std::to_string(index) + + "(_ call: UnsafeMutableRawPointer, _ args: UnsafeRawPointer?, _ " + "count: Int) {\n" + " let rt = __NSCall(call: call, args: args)\n"; + } + + std::string availabilityGuard(const Invocation& invocation, + const Symbol& symbol) const { + if (invocation.availability.empty()) { + return ""; + } + std::string platformVersion = + llvm::StringRef(invocation.availability).rsplit(',').first.trim().str(); + return " guard #available(" + invocation.availability + + ") else { return rt.throwMessage(" + + quoted(symbol.name + " requires " + platformVersion) + ") }\n"; + } + + std::string emitMember(const SwiftSurface::Member& member) { + const Symbol& symbol = *member.symbol; + const Capability& capability = *member.capability; + Invocation invocation = describeInvocation(_module, symbol, capability); + const Symbol* owner = + symbol.parentId.empty() ? nullptr : _module.find(symbol.parentId); + int ownerIndex = member.owner; + int kind = member.kind; + int flags = member.flags; + const std::string& signature = member.signature; + const BridgedType& result = member.result; + + if (kind == SwiftSurface::kEnumCase) { + // Case values are their names; nothing to call. + addRegistration(ownerIndex, kind, flags, capability.jsName, symbol.name, + signature, "nil", "nil"); + return ""; + } + + std::string code; + bool hasReceiver = invocation.needsReceiver; + int firstArgument = hasReceiver ? 1 : 0; + + // Getter or call. + int getterIndex = _thunkCount++; + code += "// " + symbol.preciseId + "\n" + thunkHeader(getterIndex); + code += availabilityGuard(invocation, symbol); + std::string receiver; + if (hasReceiver) { + receiver = bindReceiver(*owner, code); + } + std::vector arguments; + for (size_t i = 0; i < capability.parameters.size(); i++) { + std::string name = "a" + std::to_string(i); + code += readArgument(capability.parameters[i], + firstArgument + static_cast(i), name, + "argument " + std::to_string(i + 1)); + arguments.push_back(name); + } + std::string expression = + invocationExpression(invocation, receiver, arguments); + std::string binding = result.bridge == Bridge::Void ? "_" : "result"; + std::string resultType = invocation.resultType; + if (symbol.isThrowing) { + code += " do {\n let " + binding + ": " + resultType + " = " + + expression + "\n" + returnResult(result, " ") + + " } catch {\n rt.throwError(error)\n }\n"; + } else { + code += " let " + binding + ": " + resultType + " = " + expression + + "\n" + returnResult(result, " "); + } + code += "}\n\n"; + + std::string setterName = "nil"; + if (flags & SwiftSurface::kSettable) { + int setterIndex = _thunkCount++; + code += + "// " + symbol.preciseId + " (setter)\n" + thunkHeader(setterIndex); + code += availabilityGuard(invocation, symbol); + std::string setterReceiver; + if (hasReceiver) { + setterReceiver = bindReceiver(*owner, code); + } + code += + readArgument(capability.result, firstArgument, "newValue", "value"); + code += " " + + assignmentStatement(invocation, setterReceiver, "newValue") + + "\n"; + code += " rt.returnVoid()\n}\n\n"; + setterName = "__nsThunk" + std::to_string(setterIndex); + } + + addRegistration(ownerIndex, kind, flags, capability.jsName, symbol.name, + signature, "__nsThunk" + std::to_string(getterIndex), + setterName); + return code; + } + + void addRegistration(int owner, int kind, int flags, + const std::string& jsName, const std::string& swiftName, + const std::string& signature, const std::string& thunk, + const std::string& setter) { + _registrations.push_back( + " registerMember(registrar, " + std::to_string(owner) + ", " + + std::to_string(kind) + ", " + std::to_string(flags) + ", " + + quoted(jsName) + ", " + quoted(swiftName) + ", " + quoted(signature) + + ", " + thunk + ", " + setter + ")"); + } + + std::string header() const { + std::string out = "// Generated by objc-metadata-generator from the " + + _module.name + + " symbol graphs. Do not edit.\n" + "// NativeScript Swift interop thunks, ABI " + + std::to_string(kThunkABIVersion) + + ": see NativeScript/runtime/SwiftInterop.h.\n" + "import Foundation\n" + "import " + + _module.name + "\n"; + std::set overlays; + for (const auto& entry : _module.symbols) { + const Capability* capability = _classification.find(entry.first); + if (capability && capability->tier == Tier::SwiftGenerated && + !entry.second.declaringModule.empty()) { + overlays.insert(entry.second.declaringModule); + } + } + for (const auto& overlay : overlays) { + out += "import " + overlay + "\n"; + } + return out + "\n"; + } + + static std::string support() { + return R"swift(private typealias __NSThunk = @convention(c) (UnsafeMutableRawPointer, UnsafeRawPointer?, Int) -> Void +private typealias __NSRelease = @convention(c) (UnsafeMutableRawPointer) -> Void + +private final class __NSBox { + var value: Value + init(_ value: Value) { self.value = value } +} + +// Reads arguments (24-byte slots) and reports results through the runtime's +// API table, whose address is the first word of the call context. +private struct __NSCall { + let call: UnsafeMutableRawPointer + let args: UnsafeRawPointer? + + private func slot(_ index: Int, _: Function.Type) -> Function { + call.load(as: UnsafeRawPointer.self).load(fromByteOffset: index * 8, as: Function.self) + } + + func isNull(_ i: Int) -> Bool { args!.load(fromByteOffset: i * 24, as: UInt32.self) == 0 } + func bool(_ i: Int) -> Bool { args!.load(fromByteOffset: i * 24 + 8, as: UInt8.self) != 0 } + func int64(_ i: Int) -> Int64 { args!.load(fromByteOffset: i * 24 + 8, as: Int64.self) } + func uint64(_ i: Int) -> UInt64 { args!.load(fromByteOffset: i * 24 + 8, as: UInt64.self) } + func double(_ i: Int) -> Double { args!.load(fromByteOffset: i * 24 + 8, as: Double.self) } + func string(_ i: Int) -> String { + let base = args!.load(fromByteOffset: i * 24 + 8, as: UnsafePointer?.self) + let length = Int(args!.load(fromByteOffset: i * 24 + 16, as: UInt64.self)) + return String(decoding: UnsafeBufferPointer(start: base, count: length), as: UTF8.self) + } + func object(_ i: Int) -> AnyObject { + let pointer = args!.load(fromByteOffset: i * 24 + 8, as: UnsafeMutableRawPointer.self) + return Unmanaged.fromOpaque(pointer).takeUnretainedValue() + } + + func returnVoid() { + slot(0, (@convention(c) (UnsafeMutableRawPointer) -> Void).self)(call) + } + func returnBool(_ value: Bool) { + slot(1, (@convention(c) (UnsafeMutableRawPointer, UInt8) -> Void).self)(call, value ? 1 : 0) + } + func returnInt64(_ value: Int64) { + slot(2, (@convention(c) (UnsafeMutableRawPointer, Int64) -> Void).self)(call, value) + } + func returnUInt64(_ value: UInt64) { + slot(3, (@convention(c) (UnsafeMutableRawPointer, UInt64) -> Void).self)(call, value) + } + func returnDouble(_ value: Double) { + slot(4, (@convention(c) (UnsafeMutableRawPointer, Double) -> Void).self)(call, value) + } + func returnString(_ value: String) { + var value = value + value.withUTF8 { + slot(5, (@convention(c) (UnsafeMutableRawPointer, UnsafePointer?, Int) -> Void).self)( + call, $0.baseAddress, $0.count) + } + } + func returnNull() { + slot(6, (@convention(c) (UnsafeMutableRawPointer) -> Void).self)(call) + } + func returnObject(_ object: AnyObject, _ typeIndex: UInt32) { + slot(7, (@convention(c) (UnsafeMutableRawPointer, UnsafeMutableRawPointer, UInt32) -> Void).self)( + call, Unmanaged.passRetained(object).toOpaque(), typeIndex) + } + func throwError(_ error: any Error) { + report(String(describing: error), String(reflecting: type(of: error))) + } + func throwMessage(_ message: String) { + report(message, "") + } + func throwTypeError(_ message: String) { + var message = message + message.withUTF8 { + slot(9, (@convention(c) (UnsafeMutableRawPointer, UnsafePointer?, Int) -> Void).self)( + call, $0.baseAddress, $0.count) + } + } + private func report(_ message: String, _ type: String) { + var message = message + var type = type + message.withUTF8 { messageBytes in + type.withUTF8 { typeBytes in + slot(8, (@convention(c) (UnsafeMutableRawPointer, UnsafePointer?, Int, + UnsafePointer?, Int) -> Void).self)( + call, messageBytes.baseAddress, messageBytes.count, typeBytes.baseAddress, typeBytes.count) + } + } + } +} + +private func __nsRelease(_ object: UnsafeMutableRawPointer) { + Unmanaged.fromOpaque(object).release() +} + +)swift"; + } + + std::string enumHelpers() const { + std::string out; + for (const auto& type : _surface.types) { + const Symbol& symbol = *type.symbol; + if (symbol.kind != SymbolKind::Enum) { + continue; + } + std::string typeName = qualifiedTypeName(_module, symbol); + std::string availability = availabilityCondition(_module, symbol); + std::string attribute = + availability.empty() ? "" : "@available(" + availability + ")\n"; + std::string index = std::to_string(type.index); + std::vector cases; + for (const auto& id : symbol.memberIds) { + const Symbol* member = _module.find(id); + if (member && member->kind == SymbolKind::EnumCase) { + cases.push_back(member->baseName); + } + } + out += attribute + "private func __nsEnum" + index + + "(_ name: String) -> " + typeName + "? {\n switch name {\n"; + for (const auto& name : cases) { + // Qualified: a case named `none` would otherwise mean Optional.none. + out += " case " + quoted(name) + ": return " + typeName + "." + + swiftIdentifier(name) + "\n"; + } + out += " default: return nil\n }\n}\n\n"; + out += attribute + "private func __nsEnumName" + index + + "(_ value: " + typeName + ") -> String {\n switch value {\n"; + for (const auto& name : cases) { + out += " case " + typeName + "." + swiftIdentifier(name) + + ": return " + quoted(name) + "\n"; + } + out += " @unknown default: return String(describing: value)\n }\n}\n\n"; + } + return out; + } + + // Dynamic type index of a returned object: most derived classes first. + std::string typeIndexFunction() const { + std::vector classes; + for (const auto& type : _surface.types) { + if (type.symbol->kind == SymbolKind::Class || + type.symbol->kind == SymbolKind::Actor) { + classes.push_back(&type); + } + } + auto depth = [&](const Symbol* symbol) { + int value = 0; + for (const Symbol* current = symbol; + current && !current->superclassId.empty(); + current = _module.find(current->superclassId)) { + value++; + } + return value; + }; + std::stable_sort( + classes.begin(), classes.end(), + [&](const SwiftSurface::Type* a, const SwiftSurface::Type* b) { + return depth(a->symbol) > depth(b->symbol); + }); + + std::string out = + "private func __nsTypeIndex(_ object: AnyObject, _ declared: UInt32) " + "-> UInt32 {\n"; + for (const SwiftSurface::Type* type : classes) { + if (depth(type->symbol) == 0) { + // No registered subclass can be more specific than a root class. + continue; + } + std::string check = "if object is " + + qualifiedTypeName(_module, *type->symbol) + + " { return " + std::to_string(type->index) + " }"; + std::string availability = availabilityCondition(_module, *type->symbol); + if (availability.empty()) { + out += " " + check + "\n"; + } else { + out += " if #available(" + availability + ") { " + check + " }\n"; + } + } + return out + " return declared\n}\n\n"; + } + + std::string registration(const ThunkSource& result) const { + std::string out = "#if hasAttribute(c)\n@c(" + result.registerSymbol + + ")\n#else\n@_cdecl(\"" + result.registerSymbol + + "\")\n#endif\n" + "public func __nsRegister_" + + _module.name + + "(_ registrar: UnsafeMutableRawPointer) {\n" + " let api = registrar.load(as: UnsafeRawPointer.self)\n" + " let registerModule = api.load(fromByteOffset: " + + std::to_string(kRegisterModuleSlot) + + ", as: (@convention(c) (UnsafeMutableRawPointer, UInt32, " + "UnsafePointer, " + "UnsafePointer, __NSRelease) -> Void).self)\n" + " let registerType = api.load(fromByteOffset: " + + std::to_string(kRegisterTypeSlot) + + ", as: (@convention(c) (UnsafeMutableRawPointer, UInt32, " + "UInt32, UnsafePointer, " + "UnsafePointer, Int32) -> Void).self)\n" + " let registerMember = api.load(fromByteOffset: " + + std::to_string(kRegisterMemberSlot) + + ", as: (@convention(c) (UnsafeMutableRawPointer, Int32, " + "UInt32, UInt32, " + "UnsafePointer, UnsafePointer, " + "UnsafePointer, __NSThunk?, " + "__NSThunk?) -> Void).self)\n\n" + " registerModule(registrar, " + + std::to_string(kThunkABIVersion) + ", " + + quoted(_module.name) + ", " + quoted(result.fingerprint) + + ", __nsRelease)\n"; + for (const auto& type : _surface.types) { + const Symbol& symbol = *type.symbol; + int kind = type.kind; + out += " registerType(registrar, " + std::to_string(type.index) + ", " + + std::to_string(kind) + ", " + quoted(symbol.name) + ", " + + quoted(qualifiedTypeName(_module, symbol)) + ", " + + std::to_string(type.superIndex) + ")\n"; + } + for (const auto& line : _registrations) { + out += line + "\n"; + } + return out + "}\n"; + } + + std::string fingerprint(const std::vector& registrations) const { + // FNV-1a over everything registered, so the value changes with the + // surface but not with emitter formatting. + uint64_t hash = 1469598103934665603ull; + auto mix = [&](const std::string& text) { + for (unsigned char c : text) { + hash ^= c; + hash *= 1099511628211ull; + } + hash ^= '\n'; + hash *= 1099511628211ull; + }; + mix(_module.name); + for (const auto& type : _surface.types) { + mix(qualifiedTypeName(_module, *type.symbol) + "#" + + std::to_string(type.index)); + } + for (const auto& line : registrations) { + mix(line); + } + char buffer[17]; + std::snprintf(buffer, sizeof(buffer), "%016llx", + static_cast(hash)); + return buffer; + } + + const Module& _module; + const Classification& _classification; + SwiftSurface _surface; + std::vector _registrations; + int _thunkCount = 0; +}; + +} // namespace + +ThunkSource emitThunks(const Module& module, + const Classification& classification) { + return Emitter(module, classification).run(); +} + +} // namespace Swift diff --git a/metadata-generator/src/Swift/ThunkEmitter.h b/metadata-generator/src/Swift/ThunkEmitter.h new file mode 100644 index 000000000..0657601e6 --- /dev/null +++ b/metadata-generator/src/Swift/ThunkEmitter.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "CapabilityClassifier.h" +#include "SwiftIR.h" + +namespace Swift { + +// ABI version the emitted thunks implement; must match NS_SWIFT_ABI_VERSION +// in NativeScript/runtime/SwiftInterop.h, which documents the contract. +constexpr int kThunkABIVersion = 1; + +struct ThunkSource { + std::string source; + // Exported C symbol the runtime calls to register the module. + std::string registerSymbol; + // Changes whenever the registered surface changes. + std::string fingerprint; + int thunkCount = 0; +}; + +// Swift source registering every SwiftGenerated type and member of `module` +// with the NativeScript runtime, one thunk per callable. Compile it in a +// module that can import `module`. +ThunkSource emitThunks(const Module& module, + const Classification& classification); + +} // namespace Swift diff --git a/metadata-generator/src/TypeScript/SwiftDefinitionWriter.cpp b/metadata-generator/src/TypeScript/SwiftDefinitionWriter.cpp new file mode 100644 index 000000000..bb2667f8d --- /dev/null +++ b/metadata-generator/src/TypeScript/SwiftDefinitionWriter.cpp @@ -0,0 +1,595 @@ +#include "SwiftDefinitionWriter.h" + +#include + +#include +#include +#include + +#include "Swift/SwiftSource.h" +#include "Swift/SwiftSurface.h" + +namespace TypeScript { + +using namespace Swift; + +namespace { + +using Member = SwiftSurface::Member; + +// One JS name on one owner, as NativeScript/runtime/SwiftInterop.mm groups +// members. +struct Group { + int owner; + SwiftSurface::MemberKind kind; + std::string jsName; + std::vector overloads; +}; + +bool isReserved(const std::string& name) { + static const std::set reserved = { + "break", "case", "catch", "class", "const", "continue", + "debugger", "default", "delete", "do", "else", "enum", + "export", "extends", "false", "finally", "for", "function", + "if", "import", "in", "instanceof", "new", "null", + "return", "super", "switch", "this", "throw", "true", + "try", "typeof", "var", "void", "while", "with", + "yield", "let", "static", "implements", "interface", "package", + "private", "protected", "public", "await", "arguments", "eval"}; + return reserved.count(name) > 0; +} + +bool isIdentifier(const std::string& name) { + if (name.empty() || + !(llvm::isAlpha(name[0]) || name[0] == '_' || name[0] == '$')) { + return false; + } + for (char c : name) { + if (!(llvm::isAlnum(c) || c == '_' || c == '$')) { + return false; + } + } + return true; +} + +std::string propertyKey(const std::string& name) { + return isIdentifier(name) ? name : "\"" + name + "\""; +} + +std::string parameterName(const Parameter& parameter, size_t index) { + std::string name = !parameter.internalName.empty() ? parameter.internalName + : parameter.label; + if (!isIdentifier(name)) { + return "arg" + std::to_string(index); + } + return isReserved(name) ? name + "_" : name; +} + +// Swift display name of a signature code, as the runtime spells it in typed +// keys ("scale(by: Int)"). +std::string codeDisplayName(const SwiftSurface& surface, + const BridgedType& type) { + std::string name; + switch (type.bridge) { + case Bridge::Void: + name = "Void"; + break; + case Bridge::Bool: + name = "Bool"; + break; + case Bridge::Integer: { + std::string code = signatureCode(surface, type); + bool isSigned = code[0] == 'i'; + std::string bits = + llvm::StringRef(code).drop_front().take_while(llvm::isDigit).str(); + name = + std::string(isSigned ? "Int" : "UInt") + (bits == "64" ? "" : bits); + break; + } + case Bridge::Floating: + name = + unwrappedNode(type).usr() == KnownTypes::kFloat ? "Float" : "Double"; + break; + case Bridge::String: + name = "String"; + break; + case Bridge::ClassHandle: + case Bridge::StructBox: + case Bridge::EnumCase: { + int index = surface.indexOf(type.symbolId); + name = index >= 0 ? surface.types[index].symbol->name : "?"; + break; + } + case Bridge::None: + name = "?"; + break; + } + return type.optional ? name + "?" : name; +} + +std::string typedKey(const SwiftSurface& surface, const Member& member) { + const Symbol& symbol = *member.symbol; + std::string key = symbol.baseName + "("; + for (size_t i = 0; i < member.capability->parameters.size(); i++) { + if (i > 0) { + key += ", "; + } + std::string label = + i < symbol.parameters.size() ? symbol.parameters[i].label : ""; + key += (label.empty() ? "_" : label) + ": " + + codeDisplayName(surface, member.capability->parameters[i]); + } + return key + ")"; +} + +class Writer { + public: + Writer(const Module& module, const Classification& classification) + : _module(module), _surface(describeSurface(module, classification)) {} + + std::string write() { + buildGroups(); + + _out << "// Generated by objc-metadata-generator from the " << _module.name + << " symbol graphs. Do not edit.\n" + << "// The JavaScript surface ns:swift exposes for " << _module.name + << ": every declaration is backed by a generated thunk.\n\n" + << "declare module \"ns:swift/" << _module.name << "\" {\n"; + + for (const auto& type : _surface.types) { + if (type.kind == SwiftSurface::kEnum) { + writeEnum(type); + } else { + writeClass(type); + } + } + writeModuleMembers(); + + _out << "}\n\n" + << "declare module \"ns:swift\" {\n" + << " interface SwiftModules {\n" + << " " << propertyKey(_module.name) << ": typeof import(\"ns:swift/" + << _module.name << "\");\n" + << " }\n" + << "}\n"; + return _out.str(); + } + + private: + void buildGroups() { + std::map, size_t> index; + for (const auto& member : _surface.members) { + auto key = std::make_tuple(member.owner, static_cast(member.kind), + member.capability->jsName); + auto it = index.find(key); + if (it == index.end()) { + index.emplace(key, _groups.size()); + _groups.push_back( + Group{member.owner, member.kind, member.capability->jsName, {}}); + it = index.find(key); + } + _groups[it->second].overloads.push_back(&member); + } + + // Inherited overloads the subclass does not override (see BuildGroups in + // SwiftInterop.mm). + for (auto& group : _groups) { + if (group.kind != SwiftSurface::kInstanceMethod || group.owner < 0) { + continue; + } + for (int ancestor = _surface.types[group.owner].superIndex; ancestor >= 0; + ancestor = _surface.types[ancestor].superIndex) { + auto inherited = index.find(std::make_tuple( + ancestor, static_cast(group.kind), group.jsName)); + if (inherited == index.end()) { + continue; + } + for (const Member* candidate : _groups[inherited->second].overloads) { + bool overridden = false; + for (const Member* own : group.overloads) { + overridden |= own->symbol->name == candidate->symbol->name && + own->signature == candidate->signature; + } + if (!overridden) { + group.overloads.push_back(candidate); + } + } + } + } + } + + bool isA(int type, int expected) const { + for (int current = type; current >= 0; + current = _surface.types[current].superIndex) { + if (current == expected) { + return true; + } + } + return false; + } + + // Whether some JS value is accepted as both `a` and `b` (overload + // resolution in the runtime would then see both). + bool overlaps(const BridgedType& a, const BridgedType& b) const { + if (a.optional && b.optional) { + return true; + } + auto numeric = [](Bridge bridge) { + return bridge == Bridge::Integer || bridge == Bridge::Floating; + }; + auto textual = [](Bridge bridge) { + return bridge == Bridge::String || bridge == Bridge::EnumCase; + }; + if (numeric(a.bridge) && numeric(b.bridge)) { + return true; + } + if (textual(a.bridge) && textual(b.bridge)) { + return true; + } + if (a.bridge == Bridge::Bool && b.bridge == Bridge::Bool) { + return true; + } + bool objects = + (a.bridge == Bridge::ClassHandle || a.bridge == Bridge::StructBox) && + (b.bridge == Bridge::ClassHandle || b.bridge == Bridge::StructBox); + if (objects) { + int left = _surface.indexOf(a.symbolId); + int right = _surface.indexOf(b.symbolId); + return isA(left, right) || isA(right, left); + } + return false; + } + + bool ambiguousWithin(const Group& group, const Member& member) const { + const auto& parameters = member.capability->parameters; + for (const Member* other : group.overloads) { + if (other == &member || + other->capability->parameters.size() != parameters.size()) { + continue; + } + bool all = true; + for (size_t i = 0; all && i < parameters.size(); i++) { + all = overlaps(parameters[i], other->capability->parameters[i]); + } + if (all) { + return true; + } + } + return false; + } + + // Keys installed per overload when the group has several (see + // OverloadKeys in SwiftInterop.mm). + std::vector> overloadKeys( + const Group& group) const { + std::vector> keys; + if (group.overloads.size() < 2) { + return keys; + } + std::map counts; + for (const Member* member : group.overloads) { + counts[member->symbol->name]++; + } + for (const Member* member : group.overloads) { + keys.emplace_back(counts[member->symbol->name] == 1 + ? member->symbol->name + : typedKey(_surface, *member), + member); + } + return keys; + } + + std::string typeName(const BridgedType& type) const { + int index = _surface.indexOf(type.symbolId); + return index >= 0 ? _surface.types[index].symbol->name : "unknown"; + } + + std::string inputType(const BridgedType& type) const { + std::string ts; + switch (type.bridge) { + case Bridge::Bool: + ts = "boolean"; + break; + case Bridge::Integer: + ts = "number | bigint"; + break; + case Bridge::Floating: + ts = "number"; + break; + case Bridge::String: + ts = "string"; + break; + case Bridge::ClassHandle: + case Bridge::StructBox: + case Bridge::EnumCase: + ts = typeName(type); + break; + default: + ts = "never"; + break; + } + return type.optional ? ts + " | null | undefined" : ts; + } + + std::string outputType(const BridgedType& type) const { + std::string ts; + switch (type.bridge) { + case Bridge::Void: + return "void"; + case Bridge::Bool: + ts = "boolean"; + break; + case Bridge::Integer: + case Bridge::Floating: + ts = "number"; + break; + case Bridge::String: + ts = "string"; + break; + case Bridge::ClassHandle: + case Bridge::StructBox: + case Bridge::EnumCase: + ts = typeName(type); + break; + case Bridge::None: + ts = "never"; + break; + } + return type.optional ? ts + " | null" : ts; + } + + std::string parameterList(const Member& member, + const std::string& receiver = "") const { + std::vector parts; + if (!receiver.empty()) { + parts.push_back("value: " + receiver); + } + const auto& parameters = member.capability->parameters; + for (size_t i = 0; i < parameters.size(); i++) { + const Parameter* parameter = i < member.symbol->parameters.size() + ? &member.symbol->parameters[i] + : nullptr; + std::string name = + parameter ? parameterName(*parameter, i) : "arg" + std::to_string(i); + parts.push_back(name + ": " + inputType(parameters[i])); + } + return llvm::join(parts, ", "); + } + + // `{ x: number; y: number }` for initializers JS can call with labels. + std::string labeledParameters(const Member& member) const { + const auto& parameters = member.capability->parameters; + if (parameters.empty()) { + return ""; + } + std::vector fields; + for (size_t i = 0; i < parameters.size(); i++) { + const std::string& label = i < member.symbol->parameters.size() + ? member.symbol->parameters[i].label + : ""; + if (label.empty()) { + return ""; + } + fields.push_back(propertyKey(label) + ": " + inputType(parameters[i])); + } + return "{ " + llvm::join(fields, "; ") + " }"; + } + + void writeDoc(const Symbol& symbol, const std::string& indent) { + std::vector lines; + if (!symbol.docComment.empty()) { + llvm::SmallVector docLines; + llvm::StringRef(symbol.docComment).split(docLines, '\n'); + for (llvm::StringRef line : docLines) { + lines.push_back(line.str()); + } + } + for (const Availability* availability : + applicableAvailability(_module, symbol)) { + if (availability->isUnconditionallyDeprecated || + availability->deprecated) { + std::string message = availability->message; + if (message.empty() && !availability->renamed.empty()) { + message = "Renamed to `" + availability->renamed + "`."; + } + lines.push_back("@deprecated" + (message.empty() ? "" : " " + message)); + } + } + std::string condition = availabilityCondition(_module, symbol); + if (!condition.empty()) { + lines.push_back( + "@remarks Requires " + + llvm::StringRef(condition).rsplit(',').first.trim().str() + + "; throws on earlier versions."); + } + if (lines.empty()) { + return; + } + _out << indent << "/**\n"; + for (const auto& line : lines) { + std::string safe = line; + for (size_t at = safe.find("*/"); at != std::string::npos; + at = safe.find("*/")) { + safe.replace(at, 2, "* /"); + } + _out << indent << " *" << (safe.empty() ? "" : " " + safe) << "\n"; + } + _out << indent << " */\n"; + } + + void writeMethodGroup(const Group& group, const std::string& indent, + const std::string& prefix, + const std::string& receiver = "") { + for (const Member* member : group.overloads) { + if (ambiguousWithin(group, *member)) { + continue; + } + writeDoc(*member->symbol, indent); + _out << indent << prefix << propertyKey(group.jsName) << "(" + << parameterList(*member, receiver) + << "): " << outputType(member->result) << ";\n"; + } + for (const auto& key : overloadKeys(group)) { + writeDoc(*key.second->symbol, indent); + _out << indent << prefix << propertyKey(key.first) << "(" + << parameterList(*key.second, receiver) + << "): " << outputType(key.second->result) << ";\n"; + } + } + + void writeClass(const SwiftSurface::Type& type) { + const Symbol& symbol = *type.symbol; + writeDoc(symbol, " "); + _out << " export class " << symbol.name; + if (type.superIndex >= 0) { + _out << " extends " << _surface.types[type.superIndex].symbol->name; + } + _out << " {\n"; + + bool hasInitializer = false; + for (const Group& group : _groups) { + if (group.owner != type.index || + group.kind != SwiftSurface::kInitializer) { + continue; + } + hasInitializer = true; + for (const Member* member : group.overloads) { + writeDoc(*member->symbol, " "); + _out << " constructor(" << parameterList(*member) << ");\n"; + std::string labeled = labeledParameters(*member); + if (!labeled.empty()) { + _out << " constructor(args: " << labeled << ");\n"; + } + } + } + if (!hasInitializer) { + _out << " private constructor();\n"; + } + + for (const Group& group : _groups) { + if (group.owner != type.index) { + continue; + } + const Member& first = *group.overloads[0]; + switch (group.kind) { + case SwiftSurface::kInstanceProperty: + case SwiftSurface::kStaticProperty: + writeDoc(*first.symbol, " "); + _out << " " + << (group.kind == SwiftSurface::kStaticProperty ? "static " : "") + << ((first.flags & SwiftSurface::kSettable) ? "" : "readonly ") + << propertyKey(group.jsName) << ": " << outputType(first.result) + << ";\n"; + break; + case SwiftSurface::kInstanceMethod: + writeMethodGroup(group, " ", ""); + break; + case SwiftSurface::kStaticMethod: + writeMethodGroup(group, " ", "static "); + break; + default: + break; + } + } + _out << " }\n\n"; + } + + void writeEnum(const SwiftSurface::Type& type) { + const Symbol& symbol = *type.symbol; + std::vector cases; + for (const Group& group : _groups) { + if (group.owner == type.index && group.kind == SwiftSurface::kEnumCase) { + cases.push_back("\"" + group.jsName + "\""); + } + } + writeDoc(symbol, " "); + _out << " export type " << symbol.name << " = " + << (cases.empty() ? std::string("never") : llvm::join(cases, " | ")) + << ";\n"; + _out << " export const " << symbol.name << ": {\n"; + for (const Group& group : _groups) { + if (group.owner != type.index) { + continue; + } + const Member& first = *group.overloads[0]; + switch (group.kind) { + case SwiftSurface::kEnumCase: + _out << " readonly " << propertyKey(group.jsName) << ": \"" + << group.jsName << "\";\n"; + break; + case SwiftSurface::kInitializer: + // Enum initializers are exposed as `init`; they produce a case name. + for (const Member* member : group.overloads) { + writeDoc(*member->symbol, " "); + _out << " init(" << parameterList(*member) + << "): " << outputType(member->result) << ";\n"; + } + break; + case SwiftSurface::kStaticProperty: + writeDoc(*first.symbol, " "); + _out << " " + << ((first.flags & SwiftSurface::kSettable) ? "" : "readonly ") + << propertyKey(group.jsName) << ": " << outputType(first.result) + << ";\n"; + break; + case SwiftSurface::kInstanceProperty: + // A case name has no properties; instance members take it first. + writeDoc(*first.symbol, " "); + _out << " " << propertyKey(group.jsName) + << "(value: " << symbol.name << "): " << outputType(first.result) + << ";\n"; + break; + case SwiftSurface::kInstanceMethod: + writeMethodGroup(group, " ", "", symbol.name); + break; + case SwiftSurface::kStaticMethod: + writeMethodGroup(group, " ", ""); + break; + default: + break; + } + } + _out << " };\n\n"; + } + + void writeModuleMembers() { + for (const Group& group : _groups) { + if (group.owner >= 0) { + continue; + } + const Member& first = *group.overloads[0]; + if (!isIdentifier(group.jsName) || isReserved(group.jsName)) { + continue; + } + if (group.kind == SwiftSurface::kVariable) { + writeDoc(*first.symbol, " "); + _out << " export " + << ((first.flags & SwiftSurface::kSettable) ? "let " : "const ") + << group.jsName << ": " << outputType(first.result) << ";\n"; + continue; + } + for (const Member* member : group.overloads) { + if (ambiguousWithin(group, *member)) { + continue; + } + writeDoc(*member->symbol, " "); + _out << " export function " << group.jsName << "(" + << parameterList(*member) << "): " << outputType(member->result) + << ";\n"; + } + } + } + + const Module& _module; + SwiftSurface _surface; + std::vector _groups; + std::ostringstream _out; +}; + +} // namespace + +std::string SwiftDefinitionWriter::write() { + return Writer(_module, _classification).write(); +} + +} // namespace TypeScript diff --git a/metadata-generator/src/TypeScript/SwiftDefinitionWriter.h b/metadata-generator/src/TypeScript/SwiftDefinitionWriter.h new file mode 100644 index 000000000..be825314d --- /dev/null +++ b/metadata-generator/src/TypeScript/SwiftDefinitionWriter.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include "Swift/CapabilityClassifier.h" +#include "Swift/SwiftIR.h" + +namespace TypeScript { + +// Writes `swift!.d.ts`: the module's JavaScript surface as `ns:swift` +// exposes it. Only declarations with generated thunks are declared, through +// the same registration model the thunks are emitted from (SwiftSurface), so +// the declarations describe exactly what runs. +class SwiftDefinitionWriter { + public: + SwiftDefinitionWriter(const Swift::Module& module, + const Swift::Classification& classification) + : _module(module), _classification(classification) {} + + std::string write(); + + private: + const Swift::Module& _module; + const Swift::Classification& _classification; +}; + +} // namespace TypeScript diff --git a/metadata-generator/src/main.cpp b/metadata-generator/src/main.cpp index f4b7b8aee..eea794f49 100644 --- a/metadata-generator/src/main.cpp +++ b/metadata-generator/src/main.cpp @@ -1,3 +1,15 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + #include "Binary/binarySerializer.h" #include "HeadersParser/Parser.h" #include "Meta/DeclarationConverterVisitor.h" @@ -7,16 +19,16 @@ #include "Meta/Filters/ModulesBlacklist.h" #include "Meta/Filters/RemoveDuplicateMembersFilter.h" #include "Meta/Filters/ResolveGlobalNamesCollisionsFilter.h" +#include "Swift/CapabilityClassifier.h" +#include "Swift/CoverageReport.h" +#include "Swift/ProbeEmitter.h" +#include "Swift/ProbeVerifier.h" +#include "Swift/SymbolGraphLoader.h" +#include "Swift/ThunkEmitter.h" #include "TypeScript/DefinitionWriter.h" #include "TypeScript/DocSetManager.h" +#include "TypeScript/SwiftDefinitionWriter.h" #include "Yaml/YamlSerializer.h" -#include -#include -#include -#include -#include -#include -#include // Command line parameters llvm::cl::opt cla_verbose("verbose", llvm::cl::desc("Set verbose output mode"), llvm::cl::value_desc("bool")); @@ -34,6 +46,64 @@ llvm::cl::opt cla_applyManualDtsChanges("apply-manual-dts-changes", llvm llvm::cl::opt cla_clangArgumentsDelimiter(llvm::cl::Positional, llvm::cl::desc("Xclang"), llvm::cl::init("-")); llvm::cl::list cla_clangArguments(llvm::cl::ConsumeAfter, llvm::cl::desc("...")); +// Swift support +llvm::cl::opt cla_swiftSymbolGraphDir("swift-symbolgraph-dir", llvm::cl::desc("Directory containing Swift .symbolgraph files to import"), llvm::cl::value_desc("")); +llvm::cl::opt cla_skipObjC("skip-objc", llvm::cl::desc("Skip Objective-C parsing and only run Swift symbolgraph import"), llvm::cl::init(false)); +llvm::cl::opt cla_swiftIROutputDir( + "swift-ir-output", + llvm::cl::desc("Directory to write the Swift IR (.swift-ir.json) " + "for each imported module"), + llvm::cl::value_desc("")); +llvm::cl::opt cla_swiftDeploymentTarget( + "swift-deployment-target", + llvm::cl::desc("Deployment target (e.g. 15.0) for Swift availability " + "decisions; defaults to the minimum version recorded in " + "the symbol graphs"), + llvm::cl::value_desc("")); +llvm::cl::opt cla_swiftVerify( + "swift-verify", + llvm::cl::desc("Type-check the Swift-generated surface with the Swift " + "compiler and demote every declaration it rejects"), + llvm::cl::init(false)); +llvm::cl::opt cla_swiftCompiler( + "swift-compiler", + llvm::cl::desc("Swift compiler command for --swift-verify"), + llvm::cl::init("xcrun swiftc")); +llvm::cl::opt cla_swiftSDK( + "swift-sdk", llvm::cl::desc("SDK path for --swift-verify"), + llvm::cl::value_desc("")); +llvm::cl::opt cla_swiftTarget( + "swift-target", llvm::cl::desc("Target triple for --swift-verify"), + llvm::cl::value_desc("")); +llvm::cl::list cla_swiftSearchPaths( + "swift-search-path", + llvm::cl::desc("Module search path (-I) for --swift-verify"), + llvm::cl::value_desc("")); +llvm::cl::list cla_swiftFrameworkSearchPaths( + "swift-framework-search-path", + llvm::cl::desc("Framework search path (-F) for --swift-verify"), + llvm::cl::value_desc("")); +llvm::cl::opt cla_swiftWorkDir( + "swift-work-dir", + llvm::cl::desc("Scratch directory for --swift-verify (default: a " + "temporary directory)"), + llvm::cl::value_desc("")); +llvm::cl::opt cla_swiftThunkOutputDir( + "swift-thunk-output", + llvm::cl::desc("Directory to write Swift interop thunks " + "(+NativeScript.swift)"), + llvm::cl::value_desc("")); +llvm::cl::opt cla_swiftCoverageOutputDir( + "swift-coverage-output", + llvm::cl::desc("Directory to write Swift coverage reports " + "(.coverage.json)"), + llvm::cl::value_desc("")); +llvm::cl::opt cla_swiftProbeOutputDir( + "swift-probe-output", + llvm::cl::desc("Directory to write compiler-validation probes " + "(.probe.swift and .probe-map.json)"), + llvm::cl::value_desc("")); + class MetaGenerationConsumer : public clang::ASTConsumer { public: explicit MetaGenerationConsumer(clang::SourceManager& sourceManager, clang::HeaderSearch& headerSearch, Meta::ModulesBlacklist& modulesBlacklist) @@ -102,7 +172,7 @@ class MetaGenerationConsumer : public clang::ASTConsumer { file.save(cla_outputBinFile); } - // Generate TypeScript definitions + // Generate TypeScript definitions (Objective-C) if (!cla_outputDtsFolder.empty()) { llvm::sys::fs::create_directories(cla_outputDtsFolder); std::string docSetPath = cla_docSetFile.empty() ? "" : cla_docSetFile.getValue(); @@ -183,60 +253,211 @@ int main(int argc, const char** argv) TypeScript::DefinitionWriter::applyManualChanges = cla_applyManualDtsChanges; - std::vector clangArgs{ - "-v", - "-x", "objective-c", - "-fno-objc-arc", "-fmodule-maps", "-ferror-limit=0", - "-Wno-unknown-pragmas", "-Wno-ignored-attributes", "-Wno-nullability-completeness", "-Wno-expansion-to-defined", - "-D__NATIVESCRIPT_METADATA_GENERATOR=1" - }; - - // merge with hardcoded clang arguments - clangArgs.insert(clangArgs.end(), cla_clangArguments.begin(), cla_clangArguments.end()); - - // Log Clang Arguments - std::cout << "Clang Arguments: \n"; - for (const std::string& arg : clangArgs) { - std::cout << "\"" << arg << "\"," - << " "; - } - std::cout << std::endl; + if (!cla_skipObjC) { + std::vector clangArgs{ + "-v", + "-x", "objective-c", + "-fno-objc-arc", "-fmodule-maps", "-ferror-limit=0", + "-Wno-unknown-pragmas", "-Wno-ignored-attributes", "-Wno-nullability-completeness", "-Wno-expansion-to-defined", + "-D__NATIVESCRIPT_METADATA_GENERATOR=1" + }; + + // merge with hardcoded clang arguments + clangArgs.insert(clangArgs.end(), cla_clangArguments.begin(), cla_clangArguments.end()); + + // Log Clang Arguments + std::cout << "Clang Arguments: \n"; + for (const std::string& arg : clangArgs) { + std::cout << "\"" << arg << "\"," << " "; + } + std::cout << std::endl; - std::string isysroot; - std::vector::const_iterator it = std::find(clangArgs.begin(), clangArgs.end(), "-isysroot"); - if (it != clangArgs.end() && ++it != clangArgs.end()) { - isysroot = *it; - } + std::string isysroot; + std::vector::const_iterator it = std::find(clangArgs.begin(), clangArgs.end(), "-isysroot"); + if (it != clangArgs.end() && ++it != clangArgs.end()) { + isysroot = *it; + } - std::vector includePaths; - std::string umbrellaContent = CreateUmbrellaHeader(clangArgs, includePaths); + std::vector includePaths; + std::string umbrellaContent = CreateUmbrellaHeader(clangArgs, includePaths); - if (!cla_inputUmbrellaHeaderFile.empty()) { - std::ifstream fs(cla_inputUmbrellaHeaderFile); - umbrellaContent = std::string((std::istreambuf_iterator(fs)), - std::istreambuf_iterator()); - } + if (!cla_inputUmbrellaHeaderFile.empty()) { + std::ifstream fs(cla_inputUmbrellaHeaderFile); + umbrellaContent = std::string((std::istreambuf_iterator(fs)), std::istreambuf_iterator()); + } + + clangArgs.insert(clangArgs.end(), includePaths.begin(), includePaths.end()); - clangArgs.insert(clangArgs.end(), includePaths.begin(), includePaths.end()); + // Save the umbrella file + if (!cla_outputUmbrellaHeaderFile.empty()) { + std::error_code errorCode; + llvm::raw_fd_ostream umbrellaFileStream(cla_outputUmbrellaHeaderFile, errorCode, llvm::sys::fs::OpenFlags::OF_None); + if (!errorCode) { + umbrellaFileStream << umbrellaContent; + umbrellaFileStream.close(); + } + } + // generate metadata for the intermediate sdk header + Meta::ModulesBlacklist modulesBlacklist(cla_whiteListModuleRegexesFile, cla_blackListModuleRegexesFile); + clang::tooling::runToolOnCodeWithArgs(std::unique_ptr(new MetaGenerationFrontendAction(/*r*/modulesBlacklist)), umbrellaContent, clangArgs, "umbrella.h", "objc-metadata-generator"); + } - // Save the umbrella file - if (!cla_outputUmbrellaHeaderFile.empty()) { - std::error_code errorCode; - llvm::raw_fd_ostream umbrellaFileStream(cla_outputUmbrellaHeaderFile, errorCode, llvm::sys::fs::OpenFlags::OF_None); - if (!errorCode) { - umbrellaFileStream << umbrellaContent; - umbrellaFileStream.close(); + // Swift: read symbol graphs and emit TS + bool swiftFailed = false; + if (!cla_swiftSymbolGraphDir.empty()) { + Swift::ModuleSet swiftModules = + Swift::loadSymbolGraphDirectory(cla_swiftSymbolGraphDir); + for (const auto& diagnostic : swiftModules.diagnostics) { + std::cerr << (diagnostic.severity == Swift::Severity::Error + ? "error" + : "warning") + << ": swift [" << diagnostic.code << "] " + << diagnostic.file; + if (!diagnostic.symbolId.empty()) { + std::cerr << " (" << diagnostic.symbolId << ")"; + } + std::cerr << ": " << diagnostic.message << std::endl; + } + swiftFailed = swiftModules.hasErrors(); + + auto writeFile = [](llvm::StringRef folder, llvm::StringRef fileName, + const std::string& content) { + llvm::sys::fs::create_directories(folder); + llvm::SmallString<128> path; + llvm::sys::path::append(path, folder, fileName); + std::error_code error; + llvm::raw_fd_ostream file(path.str(), error, + llvm::sys::fs::OF_Text); + if (error) { + std::cerr << "error: " << path.str().str() << ": " + << error.message() << std::endl; + return false; + } + file << content; + return true; + }; + + if (!cla_swiftDeploymentTarget.empty()) { + Swift::Version target; + llvm::StringRef rest = cla_swiftDeploymentTarget.getValue(); + auto major = rest.split('.'); + auto minor = major.second.split('.'); + if (major.first.getAsInteger(10, target.major) || + (!minor.first.empty() && + minor.first.getAsInteger(10, target.minor)) || + (!minor.second.empty() && + minor.second.getAsInteger(10, target.patch))) { + std::cerr << "error: invalid --swift-deployment-target '" + << cla_swiftDeploymentTarget << "'" << std::endl; + return 1; + } + for (auto& entry : swiftModules.modules) { + entry.second.platform.minimumVersion = target; + } + } + + for (const auto& entry : swiftModules.modules) { + const Swift::Module& module = entry.second; + if (!cla_swiftIROutputDir.empty()) { + swiftFailed |= !writeFile(cla_swiftIROutputDir, + module.name + ".swift-ir.json", + Swift::dumpModuleJSON(module)); + } + if (cla_outputDtsFolder.empty() && + cla_swiftCoverageOutputDir.empty() && + cla_swiftProbeOutputDir.empty() && + cla_swiftThunkOutputDir.empty()) { + continue; + } + Swift::Classification classification; + int compilerRuns = -1; + if (cla_swiftVerify) { + Swift::VerifyOptions options; + options.compiler.clear(); + llvm::SmallVector words; + llvm::StringRef(cla_swiftCompiler).split(words, ' ', -1, false); + for (auto word : words) { + options.compiler.push_back(word.str()); + } + options.sdk = cla_swiftSDK; + options.target = cla_swiftTarget; + options.searchPaths.assign(cla_swiftSearchPaths.begin(), + cla_swiftSearchPaths.end()); + options.frameworkSearchPaths.assign( + cla_swiftFrameworkSearchPaths.begin(), + cla_swiftFrameworkSearchPaths.end()); + options.workDirectory = cla_swiftWorkDir; + if (options.workDirectory.empty()) { + llvm::SmallString<128> temporary; + llvm::sys::fs::createUniqueDirectory("ns-swift-verify", + temporary); + options.workDirectory = temporary.str().str(); + } + Swift::VerifyResult verified = + Swift::verifyWithCompiler(module, options); + if (!verified.failure.empty()) { + std::cerr << "error: swift [verification-failed] " + << module.name << ": " << verified.failure + << std::endl; + swiftFailed = true; + continue; + } + for (const auto& rejection : verified.rejections) { + std::cerr << "warning: swift [compiler-rejected] " + << module.name << " (" << rejection.first + << "): " << rejection.second << std::endl; + } + classification = std::move(verified.classification); + compilerRuns = verified.compilerRuns; + } else { + classification = Swift::classify(module); + } + if (!cla_outputDtsFolder.empty()) { + TypeScript::SwiftDefinitionWriter swiftWriter(module, + classification); + swiftFailed |= !writeFile(cla_outputDtsFolder, + "swift!" + module.name + ".d.ts", + swiftWriter.write()); + } + if (!cla_swiftCoverageOutputDir.empty()) { + swiftFailed |= !writeFile( + cla_swiftCoverageOutputDir, module.name + ".coverage.json", + Swift::coverageJSON(module, classification, compilerRuns)); + } + if (!cla_swiftThunkOutputDir.empty()) { + Swift::ThunkSource thunks = + Swift::emitThunks(module, classification); + swiftFailed |= !writeFile(cla_swiftThunkOutputDir, + module.name + "+NativeScript.swift", + thunks.source); + } + if (!cla_swiftProbeOutputDir.empty()) { + Swift::ProbeSource probes = + Swift::emitProbes(module, classification); + std::string map; + llvm::raw_string_ostream mapStream(map); + llvm::json::OStream mapJSON(mapStream, 2); + mapJSON.object([&] { + for (const auto& line : probes.lineToSymbol) { + mapJSON.attribute(std::to_string(line.first), line.second); + } + }); + mapStream << "\n"; + mapStream.flush(); + swiftFailed |= + !writeFile(cla_swiftProbeOutputDir, + module.name + ".probe.swift", probes.source); + swiftFailed |= !writeFile(cla_swiftProbeOutputDir, + module.name + ".probe-map.json", map); } + } } - // generate metadata for the intermediate sdk header - Meta::ModulesBlacklist modulesBlacklist(cla_whiteListModuleRegexesFile, cla_blackListModuleRegexesFile); - clang::tooling::runToolOnCodeWithArgs(std::unique_ptr(new MetaGenerationFrontendAction(/*r*/modulesBlacklist)), umbrellaContent, clangArgs, "umbrella.h", "objc-metadata-generator"); std::clock_t end = clock(); double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC; std::cout << "Done! Running time: " << elapsed_secs << " sec " << std::endl; - return 0; + return swiftFailed ? 1 : 0; } catch (const std::exception& e) { std::cerr << "error: " << e.what() << std::endl; return 1; diff --git a/metadata-generator/tests/CMakeLists.txt b/metadata-generator/tests/CMakeLists.txt new file mode 100644 index 000000000..c2adca4d9 --- /dev/null +++ b/metadata-generator/tests/CMakeLists.txt @@ -0,0 +1,37 @@ +set(SWIFT_GENERATOR_SOURCES + ${CMAKE_SOURCE_DIR}/src/Swift/CapabilityClassifier.cpp + ${CMAKE_SOURCE_DIR}/src/Swift/CoverageReport.cpp + ${CMAKE_SOURCE_DIR}/src/Swift/FragmentTokens.cpp + ${CMAKE_SOURCE_DIR}/src/Swift/ProbeEmitter.cpp + ${CMAKE_SOURCE_DIR}/src/Swift/ProbeVerifier.cpp + ${CMAKE_SOURCE_DIR}/src/Swift/SwiftIR.cpp + ${CMAKE_SOURCE_DIR}/src/Swift/SwiftSource.cpp + ${CMAKE_SOURCE_DIR}/src/Swift/SwiftSurface.cpp + ${CMAKE_SOURCE_DIR}/src/Swift/SwiftTypes.cpp + ${CMAKE_SOURCE_DIR}/src/Swift/SymbolGraphLoader.cpp + ${CMAKE_SOURCE_DIR}/src/Swift/ThunkEmitter.cpp + ${CMAKE_SOURCE_DIR}/src/TypeScript/SwiftDefinitionWriter.cpp +) + +add_executable(swift-symbolgraph-tests + swift/TestMain.cpp + swift/SymbolGraphLoaderTests.cpp + swift/SwiftTypesTests.cpp + swift/ClassifierTests.cpp + swift/ThunkEmitterTests.cpp + ${SWIFT_GENERATOR_SOURCES} +) +target_include_directories(swift-symbolgraph-tests PRIVATE ${CMAKE_SOURCE_DIR}/src) +target_compile_definitions(swift-symbolgraph-tests PRIVATE + SWIFT_FIXTURE_DIR="${CMAKE_SOURCE_DIR}/TestFixtures/SwiftDemo" + SWIFT_FIXTURE_GRAPHS_DIR="${CMAKE_SOURCE_DIR}/TestFixtures/SwiftDemo/symbolgraphs" + SWIFT_SNAPSHOT_DIR="${CMAKE_CURRENT_SOURCE_DIR}/swift/snapshots" + SWIFT_TEST_DIR="${CMAKE_CURRENT_SOURCE_DIR}/swift" + SWIFT_TYPES_DIR="${CMAKE_SOURCE_DIR}/../types" +) +target_link_libraries(swift-symbolgraph-tests ${LLVM_LINKER_FLAGS}) +set_target_properties(swift-symbolgraph-tests PROPERTIES + COMPILE_FLAGS "-Werror -Wall -Wextra -Wno-unused-parameter" +) + +add_test(NAME swift-symbolgraph-tests COMMAND swift-symbolgraph-tests) diff --git a/metadata-generator/tests/swift/ClassifierTests.cpp b/metadata-generator/tests/swift/ClassifierTests.cpp new file mode 100644 index 000000000..4e915eadc --- /dev/null +++ b/metadata-generator/tests/swift/ClassifierTests.cpp @@ -0,0 +1,247 @@ +#include +#include + +#include "Swift/CapabilityClassifier.h" +#include "Swift/CoverageReport.h" +#include "Swift/ProbeEmitter.h" +#include "Swift/ProbeVerifier.h" +#include "Swift/SwiftSource.h" +#include "SwiftToolchain.h" +#include "TestHarness.h" +#include "TestSupport.h" + +using namespace Swift; +using namespace TestSupport; + +namespace { + +const Classification& classification() { + static Classification result = classify(demo()); + return result; +} + +const Capability* capabilityAt(const std::string& path) { + const Symbol* symbol = symbolAt(demo(), path); + return symbol ? classification().find(symbol->preciseId) : nullptr; +} + +void expectTier(const char* file, int line, const std::string& path, Tier tier, + const std::string& reason = "") { + const Capability* capability = capabilityAt(path); + if (!capability) { + TestHarness::fail(file, line, "no single symbol at " + path); + return; + } + std::string actualReasons = llvm::join(capability->reasons, ","); + if (capability->tier != tier || actualReasons != reason) { + TestHarness::fail(file, line, + path + ": expected " + toString(tier) + "(" + reason + + "), got " + toString(capability->tier) + "(" + + actualReasons + ")"); + } +} + +#define EXPECT_TIER(...) expectTier(__FILE__, __LINE__, __VA_ARGS__) + +} // namespace + +TEST(ClassifyNominalTypes) { + EXPECT_TIER("Demo", Tier::SwiftGenerated); + EXPECT_TIER("Point", Tier::SwiftGenerated); + EXPECT_TIER("Flavor", Tier::SwiftGenerated); + EXPECT_TIER("Counter", Tier::SwiftGenerated); + EXPECT_TIER("Canvas", Tier::SwiftGenerated); + EXPECT_TIER("Greeter", Tier::TypeOnly, "protocol"); + EXPECT_TIER("Measurement", Tier::Unsupported, "enum-associated-values"); + EXPECT_TIER("ShapeError", Tier::Unsupported, "enum-associated-values"); + EXPECT_TIER("Measurement.Unit", Tier::Unsupported, "nested-type"); + EXPECT_TIER("Coordinates", Tier::TypeOnly, "type-alias"); +} + +TEST(ClassifyCallables) { + EXPECT_TIER("Demo.init()", Tier::SwiftGenerated); + EXPECT_TIER("Demo.greet(name:)", Tier::SwiftGenerated); + EXPECT_TIER("Demo.greet(name:times:)", Tier::SwiftGenerated); + EXPECT_TIER("Demo.version", Tier::SwiftGenerated); + EXPECT_TIER("Point.x", Tier::SwiftGenerated); + EXPECT_TIER("Point.init(x:y:)", Tier::SwiftGenerated); + EXPECT_TIER("Point.description", Tier::SwiftGenerated); + EXPECT_TIER("Flavor.vanilla", Tier::SwiftGenerated); + EXPECT_TIER("Flavor.init(rawValue:)", Tier::SwiftGenerated); + EXPECT_TIER("Flavor.hashValue", Tier::SwiftGenerated); + EXPECT_TIER("Polygon.init(name:)", Tier::SwiftGenerated); + EXPECT_TIER("Polygon.describe(_:)", Tier::SwiftGenerated); + EXPECT_TIER("Polygon.make()", Tier::SwiftGenerated); + EXPECT_TIER("Polygon.shared", Tier::SwiftGenerated); + EXPECT_TIER("Ring.expand(by:)", Tier::SwiftGenerated); + EXPECT_TIER("Loader.load(path:)", Tier::Unsupported, + "unbridged-type:Foundation.Data"); + EXPECT_TIER("Loader.modernOnly()", Tier::SwiftGenerated); + EXPECT_TIER("Loader.legacyFetch()", Tier::SwiftGenerated); + EXPECT_TIER("makeDefaultPoint()", Tier::SwiftGenerated); + EXPECT_TIER("defaultFlavor", Tier::SwiftGenerated); + EXPECT_TIER("globalCounter", Tier::SwiftGenerated); + EXPECT_TIER("Counter.init()", Tier::SwiftGenerated); + EXPECT_TIER("Counter.label()", Tier::SwiftGenerated); +} + +TEST(ClassifyRejections) { + EXPECT_TIER("Greeter.greet(name:)", Tier::TypeOnly, "protocol-requirement"); + EXPECT_TIER("Loader.fetch(url:)", Tier::Unsupported, "async"); + EXPECT_TIER("Loader.wait(seconds:)", Tier::Unsupported, "async"); + EXPECT_TIER("Loader.transform(_:)", Tier::SwiftSpecialized, "generic"); + EXPECT_TIER("Loader.first(of:)", Tier::SwiftSpecialized, "generic"); + EXPECT_TIER("Loader.withCompletion(_:)", Tier::Unsupported, "closure"); + EXPECT_TIER("Loader.each(_:)", Tier::Unsupported, "closure"); + EXPECT_TIER("Loader.update(_:)", Tier::Unsupported, "inout-parameter"); + EXPECT_TIER("Loader.lookup(table:key:)", Tier::Unsupported, "collection"); + EXPECT_TIER("Counter.increment()", Tier::Unsupported, "actor-isolated"); + EXPECT_TIER("Counter.value", Tier::Unsupported, "actor-isolated"); + EXPECT_TIER("Canvas.init()", Tier::Unsupported, "main-actor"); + EXPECT_TIER("Canvas.draw(_:)", Tier::Unsupported, "main-actor"); + EXPECT_TIER("Ring.+(_:_:)", Tier::Unsupported, "operator"); + EXPECT_TIER("Polygon.subscript(_:)", Tier::Unsupported, "subscript"); + EXPECT_TIER("String.shouted", Tier::Unsupported, "external-type-extension"); + EXPECT_TIER("Measurement.isNone", Tier::Unsupported, "owner-not-bridged"); + EXPECT_TIER("Flavor.hash(into:)", Tier::Unsupported, "inout-parameter"); +} + +TEST(ClassifyBridges) { + const Capability* describe = capabilityAt("Polygon.describe(_:)"); + REQUIRE(describe && describe->parameters.size() == 1); + CHECK(describe->parameters[0].bridge == Bridge::ClassHandle); + CHECK(describe->parameters[0].optional); + CHECK(describe->result.bridge == Bridge::String); + + const Capability* rawValue = capabilityAt("Flavor.init(rawValue:)"); + REQUIRE(rawValue); + CHECK(rawValue->result.bridge == Bridge::EnumCase); + CHECK(rawValue->result.optional); + CHECK(rawValue->parameters[0].bridge == Bridge::Integer); + + const Capability* point = capabilityAt("makeDefaultPoint()"); + REQUIRE(point); + CHECK(point->result.bridge == Bridge::StructBox); + CHECK(point->result.symbolId == symbolAt(demo(), "Point")->preciseId); +} + +TEST(ClassifyJsNamesAndOverloads) { + for (const Symbol* overload : symbolsAt(demo(), "Polygon.scale(by:)")) { + const Capability* capability = classification().find(overload->preciseId); + REQUIRE(capability); + CHECK_EQ(capability->jsName, std::string("scale")); + // Double and Int are both JS numbers. + CHECK(capability->ambiguousOverload); + } + CHECK(!capabilityAt("Polygon.scale(x:y:)")->ambiguousOverload); + CHECK(!capabilityAt("Demo.greet(name:)")->ambiguousOverload); + CHECK_EQ(capabilityAt("Demo.greet(name:times:)")->jsName, + std::string("greet")); + CHECK_EQ(capabilityAt("Polygon.init(name:vertexCount:)")->jsName, + std::string("constructor")); + CHECK(!capabilityAt("Polygon.init(name:vertexCount:)")->ambiguousOverload); +} + +TEST(InvocationAvailability) { + const Symbol* modern = symbolAt(demo(), "Loader.modernOnly()"); + REQUIRE(modern); + Invocation invocation = describeInvocation( + demo(), *modern, *classification().find(modern->preciseId)); + CHECK_EQ(invocation.availability, std::string("iOS 16.0, *")); + + const Symbol* old = symbolAt(demo(), "Loader.oldFetch()"); + REQUIRE(old); + Invocation unguarded = + describeInvocation(demo(), *old, *classification().find(old->preciseId)); + CHECK_EQ(unguarded.availability, std::string()); +} + +TEST(CoverageSnapshot) { + checkSnapshot("SwiftDemo.coverage.json", + coverageJSON(demo(), classification())); +} + +TEST(ProbeSnapshot) { + checkSnapshot("SwiftDemo.probe.swift", + emitProbes(demo(), classification()).source); +} + +TEST(VerifierParsesDiagnostics) { + std::string log = + "/tmp/p.swift:12:7: error: value of type 'X' has no member 'y'\n" + "/tmp/p.swift:12:9: error: second error on the same probe\n" + "/tmp/p.swift:13:1: warning: ignored\n" + "/tmp/other.swift:4:1: error: not ours\n" + "/tmp/p.swift:99:1: error: outside probes\n"; + std::map lines = {{12, "s:sym"}, {13, "s:sym"}}; + std::vector unmapped; + auto rejections = rejectionsFromLog(log, "/tmp/p.swift", lines, unmapped); + REQUIRE(rejections.size() == 1); + CHECK_EQ(rejections.at("s:sym"), + std::string("value of type 'X' has no member 'y'")); + REQUIRE(unmapped.size() == 1); + CHECK_EQ(unmapped[0], std::string("99: outside probes")); +} + +TEST(VerifierAcceptsFixture) { + if (fixtureModuleDirectory().empty()) { + std::cout << " (skipped: no Swift toolchain)" << std::endl; + return; + } + VerifyOptions options = fixtureVerifyOptions(); + VerifyResult result = verifyWithCompiler(demo(), options); + llvm::sys::fs::remove_directories(options.workDirectory); + CHECK_EQ(result.failure, std::string()); + CHECK_EQ(result.compilerRuns, 1); + CHECK(result.rejections.empty()); +} + +TEST(VerifierDemotesWhatTheCompilerRejects) { + if (fixtureModuleDirectory().empty()) { + std::cout << " (skipped: no Swift toolchain)" << std::endl; + return; + } + // An IR that disagrees with the compiler: greet(name:) takes a String, not + // an Int. + Module wrong = demo(); + Symbol* greet = nullptr; + for (auto& entry : wrong.symbols) { + if (llvm::join(entry.second.pathComponents, ".") == "Demo.greet(name:)") { + greet = &entry.second; + } + } + REQUIRE(greet && greet->parameters.size() == 1); + greet->parameters[0].type = + TypeRef{"Int", {Fragment{"typeIdentifier", "Int", "s:Si"}}}; + + VerifyOptions options = fixtureVerifyOptions(); + VerifyResult result = verifyWithCompiler(wrong, options); + llvm::sys::fs::remove_directories(options.workDirectory); + CHECK_EQ(result.failure, std::string()); + CHECK_EQ(result.compilerRuns, 2); + REQUIRE(result.rejections.size() == 1); + CHECK(result.rejections.count(greet->preciseId)); + const Capability* demoted = result.classification.find(greet->preciseId); + REQUIRE(demoted); + CHECK(demoted->tier == Tier::Unsupported); + CHECK( + llvm::StringRef(demoted->reasons.at(0)).startswith("compiler-rejected:")); + + const Symbol* other = symbolAt(demo(), "Demo.greet(name:times:)"); + CHECK(result.classification.find(other->preciseId)->tier == + Tier::SwiftGenerated); +} + +// Type-checks the probes against the separately compiled fixture module. +TEST(ProbesTypeCheck) { + if (fixtureModuleDirectory().empty()) { + std::cout << " (skipped: no Swift toolchain)" << std::endl; + return; + } + std::string errors = + typeCheckAgainstFixture(emitProbes(demo(), classification()).source); + if (!errors.empty()) { + TestHarness::fail(__FILE__, __LINE__, + "probes failed to type-check:\n" + errors); + } +} diff --git a/metadata-generator/tests/swift/SwiftToolchain.h b/metadata-generator/tests/swift/SwiftToolchain.h new file mode 100644 index 000000000..22b75eace --- /dev/null +++ b/metadata-generator/tests/swift/SwiftToolchain.h @@ -0,0 +1,105 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +#include "Swift/ProbeVerifier.h" + +// Helpers for tests that run the Swift compiler against the fixture module. +namespace TestSupport { + +// Directory holding SwiftDemo.swiftmodule built from the fixture sources, or +// "" when no Swift toolchain is available. +inline const std::string& fixtureModuleDirectory() { + static std::string directory = [] { + if (!llvm::sys::findProgramByName("xcrun")) { + return std::string(); + } + llvm::SmallString<128> path; + if (llvm::sys::fs::createUniqueDirectory("swift-fixture", path)) { + return std::string(); + } + std::string command = + "xcrun swiftc -emit-module -module-name SwiftDemo " + "-target arm64-apple-ios15.0-simulator " + "-sdk \"$(xcrun --sdk iphonesimulator --show-sdk-path)\" " + "-emit-module-path '" + + path.str().str() + + "/SwiftDemo.swiftmodule' '" SWIFT_FIXTURE_DIR + "'/Sources/SwiftDemo/*.swift"; + auto shell = llvm::sys::findProgramByName("sh"); + if (!shell || + llvm::sys::ExecuteAndWait(*shell, {*shell, "-c", command}) != 0) { + return std::string(); + } + return path.str().str(); + }(); + return directory; +} + +inline Swift::VerifyOptions fixtureVerifyOptions() { + Swift::VerifyOptions options; + options.compiler = {"xcrun", "swiftc"}; + llvm::SmallString<128> sdkLog; + llvm::sys::fs::createTemporaryFile("sdk", "txt", sdkLog); + auto shell = llvm::sys::findProgramByName("sh"); + std::optional redirects[] = { + std::nullopt, llvm::StringRef(sdkLog), std::nullopt}; + llvm::sys::ExecuteAndWait( + *shell, {*shell, "-c", "xcrun --sdk iphonesimulator --show-sdk-path"}, + std::nullopt, redirects); + auto sdk = llvm::MemoryBuffer::getFile(sdkLog); + options.sdk = sdk ? (*sdk)->getBuffer().trim().str() : ""; + llvm::sys::fs::remove(sdkLog); + options.target = "arm64-apple-ios15.0-simulator"; + options.searchPaths = {fixtureModuleDirectory()}; + llvm::SmallString<128> work; + llvm::sys::fs::createUniqueDirectory("swift-verify", work); + options.workDirectory = work.str().str(); + return options; +} + +// Type-checks `source` against the fixture module; returns the compiler's +// output on failure and "" on success. +inline std::string typeCheckAgainstFixture(const std::string& source, + const std::string& extraFlags = "") { + llvm::SmallString<128> directory; + if (llvm::sys::fs::createUniqueDirectory("swift-typecheck", directory)) { + return "cannot create a temporary directory"; + } + llvm::SmallString<128> sourcePath(directory); + llvm::sys::path::append(sourcePath, "source.swift"); + { + std::error_code error; + llvm::raw_fd_ostream out(sourcePath, error, llvm::sys::fs::OF_Text); + out << source; + } + llvm::SmallString<128> log(directory); + llvm::sys::path::append(log, "swiftc.log"); + std::string command = + "xcrun swiftc -typecheck " + extraFlags + + " -target arm64-apple-ios15.0-simulator " + "-sdk \"$(xcrun --sdk iphonesimulator --show-sdk-path)\" -I '" + + fixtureModuleDirectory() + "' '" + sourcePath.str().str() + "'"; + auto shell = llvm::sys::findProgramByName("sh"); + std::optional redirects[] = { + std::nullopt, llvm::StringRef(log), llvm::StringRef(log)}; + int status = llvm::sys::ExecuteAndWait(*shell, {*shell, "-c", command}, + std::nullopt, redirects); + std::string output; + if (status != 0) { + auto buffer = llvm::MemoryBuffer::getFile(log); + output = buffer ? (*buffer)->getBuffer().str() + : "compiler failed without output"; + } + llvm::sys::fs::remove_directories(directory); + return output; +} + +} // namespace TestSupport diff --git a/metadata-generator/tests/swift/SwiftTypesTests.cpp b/metadata-generator/tests/swift/SwiftTypesTests.cpp new file mode 100644 index 000000000..754291ed1 --- /dev/null +++ b/metadata-generator/tests/swift/SwiftTypesTests.cpp @@ -0,0 +1,215 @@ +#include "Swift/SwiftTypes.h" +#include "TestHarness.h" +#include "TestSupport.h" + +using namespace Swift; +using namespace TestSupport; + +namespace { + +TypeRef ref(std::vector fragments) { + TypeRef type; + for (const auto& fragment : fragments) { + type.spelling += fragment.spelling; + } + type.fragments = std::move(fragments); + return type; +} + +Fragment id(const std::string& name, const std::string& usr = "") { + return Fragment{"typeIdentifier", name, usr}; +} + +Fragment text(const std::string& spelling) { + return Fragment{"text", spelling, ""}; +} + +Fragment keyword(const std::string& spelling) { + return Fragment{"keyword", spelling, ""}; +} + +TypeNode parse(const TypeRef& type, std::set generics = {}, + bool expectComplete = true) { + bool complete = false; + TypeNode node = parseType(type, generics, &complete); + if (complete != expectComplete) { + TestHarness::fail(__FILE__, __LINE__, + "parse of '" + type.spelling + + "' complete=" + std::to_string(complete)); + } + return node; +} + +using Kind = TypeNode::Kind; + +} // namespace + +TEST(TypesOptionalNominal) { + TypeNode node = + parse(ref({id("Polygon", "s:9SwiftDemo7PolygonC"), text("?")})); + CHECK(node.kind == Kind::Optional); + REQUIRE(node.children.size() == 1); + CHECK(node.children[0].kind == Kind::Nominal); + CHECK_EQ(node.children[0].usr(), std::string("s:9SwiftDemo7PolygonC")); + CHECK_EQ(spelling(node), std::string("Polygon?")); +} + +TEST(TypesNamedGenericsNormalize) { + TypeNode optional = parse( + ref({id("Optional", "s:Sq"), text("<"), id("Int", "s:Si"), text(">")})); + CHECK(optional.kind == Kind::Optional); + TypeNode array = parse( + ref({id("Array", "s:Sa"), text("<"), id("Int", "s:Si"), text(">")})); + CHECK(array.kind == Kind::Array); + TypeNode voidType = parse(ref({id("Void", "s:s4Voida")})); + CHECK(voidType.kind == Kind::Void); + TypeNode empty = parse(ref({text("()")})); + CHECK(empty.kind == Kind::Void); +} + +TEST(TypesCollections) { + TypeNode dictionary = parse(ref({text("["), id("String", "s:SS"), text(" : "), + id("Int", "s:Si"), text("]")})); + CHECK(dictionary.kind == Kind::Dictionary); + CHECK_EQ(spelling(dictionary), std::string("[String: Int]")); + + TypeNode array = + parse(ref({text("["), id("Element"), text("]")}), {"Element"}); + CHECK(array.kind == Kind::Array); + CHECK(array.children[0].kind == Kind::GenericParameter); +} + +TEST(TypesFunctions) { + TypeNode completion = parse(ref( + {text("("), id("Result", "s:s6ResultO"), text("<"), id("String", "s:SS"), + text(", "), id("ShapeError", "s:9SwiftDemo10ShapeErrorO"), + text(">) -> "), id("Void", "s:s4Voida")})); + CHECK(completion.kind == Kind::Function); + REQUIRE(completion.children.size() == 1); + CHECK_EQ(completion.children[0].components[0].arguments.size(), size_t(2)); + REQUIRE(completion.result.size() == 1); + CHECK(completion.result[0].kind == Kind::Void); + CHECK_EQ(spelling(completion), + std::string("(Result) -> Void")); + + TypeNode effects = + parse(ref({text("("), keyword("any"), text(" "), id("SerialExecutor"), + text(") "), keyword("throws"), text("("), id("E"), + text(") -> "), id("T")}), + {"E", "T"}); + CHECK(effects.kind == Kind::Function); + CHECK(effects.isThrowing); + REQUIRE(effects.thrownType.size() == 1); + CHECK(effects.thrownType[0].kind == Kind::GenericParameter); + CHECK(effects.children[0].kind == Kind::Existential); + CHECK_EQ(spelling(effects), + std::string("(any SerialExecutor) throws(E) -> T")); + + TypeNode isolated = + parse(ref({Fragment{"attribute", "@", ""}, id("MainActor", "s:ScM"), + text(" ("), id("Message"), text(") "), keyword("async"), + text(" -> "), id("Void", "s:s4Voida")})); + CHECK(isolated.kind == Kind::Function); + CHECK(isolated.isAsync); + CHECK(isolated.hasAttribute("@MainActor")); + + TypeNode optionalClosure = + parse(ref({text("(("), id("URL"), text(", any "), id("Error"), + text(") -> "), id("Bool"), text(")?")})); + CHECK(optionalClosure.kind == Kind::Optional); + CHECK(optionalClosure.children[0].kind == Kind::Function); + CHECK_EQ(spelling(optionalClosure), + std::string("((URL, any Error) -> Bool)?")); +} + +TEST(TypesTuplesKeepLabels) { + TypeNode tuple = + parse(ref({text("(latitude: "), id("Double", "s:Sd"), + text(", longitude: "), id("Double", "s:Sd"), text(")")})); + CHECK(tuple.kind == Kind::Tuple); + CHECK_EQ(llvm::join(tuple.labels, ","), std::string("latitude,longitude")); + CHECK_EQ(spelling(tuple), + std::string("(latitude: Double, longitude: Double)")); +} + +TEST(TypesMemberAndMetatypes) { + TypeNode member = + parse(ref({id("AttributedString"), text("."), id("Index", "s:index")})); + CHECK(member.kind == Kind::Nominal); + CHECK_EQ(member.components.size(), size_t(2)); + CHECK_EQ(member.usr(), std::string("s:index")); + + TypeNode dependent = parse(ref({id("T"), text("."), id("Value")}), {"T"}); + CHECK(dependent.kind == Kind::GenericParameter); + CHECK_EQ(spelling(dependent), std::string("T.Value")); + + TypeNode metatype = parse(ref({id("T"), text(".Type")}), {"T"}); + CHECK(metatype.kind == Kind::Metatype); + CHECK_EQ(spelling(metatype), std::string("T.Type")); + + TypeNode nested = parse(ref({id("KeyPath"), text("<"), id("Scopes"), + text(", "), id("S"), text(".Type>")}), + {"S"}); + CHECK(nested.kind == Kind::Nominal); + CHECK(nested.components[0].arguments[1].kind == Kind::Metatype); +} + +TEST(TypesExistentialsAndCompositions) { + TypeNode opaque = parse(ref({keyword("some"), text(" "), id("View")})); + CHECK(opaque.kind == Kind::Opaque); + + TypeNode composition = + parse(ref({text("any "), id("AnyKeyPath"), text(" & "), id("Sendable")})); + CHECK(composition.kind == Kind::Existential); + CHECK(composition.children[0].kind == Kind::Composition); + CHECK_EQ(spelling(composition), std::string("any AnyKeyPath & Sendable")); + + TypeNode anyType = parse(ref({keyword("Any")})); + CHECK(anyType.kind == Kind::Existential); + CHECK_EQ(spelling(anyType), std::string("Any")); +} + +TEST(TypesIsolationAttributeOnClosure) { + TypeNode node = + parse(ref({keyword("nonisolated"), text("(nonsending) ("), keyword("any"), + text(" "), id("SerialExecutor"), text(") "), keyword("async"), + text(" -> "), id("T")}), + {"T"}); + CHECK(node.kind == Kind::Function); + CHECK(node.hasAttribute("nonisolated(nonsending)")); +} + +TEST(TypesParameterPacksAreIncomplete) { + parse(ref({id("Predicate"), text("")}), + {"Input"}, + /*expectComplete*/ false); +} + +TEST(TypesEveryFixtureTypeParses) { + for (const auto& entry : demo().symbols) { + const Symbol& symbol = entry.second; + std::set generics = genericNamesInScope(demo(), symbol); + std::vector types; + for (const auto& parameter : symbol.parameters) { + types.push_back(¶meter.type); + } + if (symbol.returnType) { + types.push_back(&*symbol.returnType); + } + if (symbol.valueType) { + types.push_back(&*symbol.valueType); + } + if (symbol.aliasedType) { + types.push_back(&*symbol.aliasedType); + } + for (const TypeRef* type : types) { + bool complete = false; + parseType(*type, generics, &complete); + if (!complete) { + TestHarness::fail( + __FILE__, __LINE__, + "incomplete parse of '" + type->spelling + "' in " + symbol.name); + } + } + } +} diff --git a/metadata-generator/tests/swift/SymbolGraphLoaderTests.cpp b/metadata-generator/tests/swift/SymbolGraphLoaderTests.cpp new file mode 100644 index 000000000..4c02843f9 --- /dev/null +++ b/metadata-generator/tests/swift/SymbolGraphLoaderTests.cpp @@ -0,0 +1,679 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include "Swift/CapabilityClassifier.h" +#include "Swift/SymbolGraphLoader.h" +#include "TestHarness.h" +#include "TestSupport.h" +#include "TypeScript/SwiftDefinitionWriter.h" + +using namespace Swift; +using namespace TestSupport; + +namespace { + +ModuleSet loadBuffers( + const std::vector>& buffers) { + SymbolGraphLoader loader; + for (const auto& buffer : buffers) { + loader.addBuffer(buffer.second, buffer.first); + } + return loader.finish(); +} + +std::string graphJSON(const std::string& symbols, + const std::string& relationships, + const std::string& format = "0.6.0") { + auto parts = llvm::StringRef(format).split('.'); + auto minorPatch = parts.second.split('.'); + return R"({"metadata":{"formatVersion":{"major":)" + parts.first.str() + + R"(,"minor":)" + minorPatch.first.str() + R"(,"patch":)" + + minorPatch.second.str() + + R"(},"generator":"test"},"module":{"name":"Mini","platform":{}},"symbols":[)" + + symbols + R"(],"relationships":[)" + relationships + "]}"; +} + +// `owner` is the dot-separated path of the containing type, if any. +std::string symbolJSON(const std::string& id, const std::string& kind, + const std::string& name, const std::string& declaration, + const std::string& owner = "") { + std::string path; + for (llvm::StringRef rest = owner; !rest.empty();) { + auto split = rest.split('.'); + path += "\"" + split.first.str() + "\","; + rest = split.second; + } + path += "\"" + name + "\""; + return R"({"kind":{"identifier":")" + kind + + R"("},"identifier":{"precise":")" + id + R"("},"pathComponents":[)" + + path + + R"(],"names":{"title":"x"},"accessLevel":"public","declarationFragments":[)" + + declaration + "]}"; +} + +} // namespace + +TEST(LoadsFixtureWithoutDiagnostics) { + CHECK_EQ(fixture().modules.size(), size_t(1)); + CHECK_EQ(diagnosticCodes(fixture().diagnostics), std::string()); + const Module& module = demo(); + CHECK_EQ(module.name, std::string("SwiftDemo")); + CHECK_EQ(module.graphFiles.size(), size_t(2)); + CHECK_EQ(module.platform.operatingSystem, std::string("ios")); + CHECK_EQ(module.platform.environment, std::string("simulator")); +} + +TEST(TopLevelDeclarationsInSourceOrder) { + std::vector names; + for (const auto& id : demo().topLevelIds) { + names.push_back(demo().find(id)->name); + } + std::vector expected = { + "Greeter", "Demo", "Point", + "Flavor", "Shape", "Polygon", + "Square", "Precipitation", "ShapeError", + "Measurement", "Ring", "Counter", + "Canvas", "Loader", "makeDefaultPoint()", + "defaultFlavor", "globalCounter", "Coordinates", + "checkedSide(_:)", "echoInt8(_:)", "echoUInt64(_:)", + "largestInt()", "shout(_:)", "Tracker"}; + CHECK_EQ(llvm::join(names, ","), llvm::join(expected, ",")); +} + +TEST(NominalKinds) { + CHECK(symbolAt(demo(), "Demo")->kind == SymbolKind::Class); + CHECK(symbolAt(demo(), "Point")->kind == SymbolKind::Struct); + CHECK(symbolAt(demo(), "Flavor")->kind == SymbolKind::Enum); + CHECK(symbolAt(demo(), "Greeter")->kind == SymbolKind::Protocol); + CHECK(symbolAt(demo(), "Counter")->kind == SymbolKind::Actor); + CHECK(symbolAt(demo(), "Polygon")->access == AccessLevel::Open); + CHECK(symbolAt(demo(), "Demo")->access == AccessLevel::Public); +} + +TEST(ExtensionMembersJoinTheirType) { + const Symbol* demoType = symbolAt(demo(), "Demo"); + REQUIRE(demoType); + auto names = memberNames(demo(), *demoType); + CHECK(contains(names, "init()")); + CHECK(contains(names, "greet(name:)")); + CHECK(contains(names, "greet(name:times:)")); + CHECK(contains(names, "version")); + + const Symbol* version = symbolAt(demo(), "Demo.version"); + REQUIRE(version); + CHECK(version->isStatic); + CHECK_EQ(version->parentId, demoType->preciseId); +} + +TEST(OverloadsKeepDistinctIdentities) { + auto overloads = symbolsAt(demo(), "Polygon.scale(by:)"); + REQUIRE(overloads.size() == 2); + CHECK(overloads[0]->preciseId != overloads[1]->preciseId); + std::vector types; + for (const Symbol* overload : overloads) { + REQUIRE(overload->parameters.size() == 1); + CHECK_EQ(overload->parameters[0].label, std::string("by")); + CHECK_EQ(overload->parameters[0].internalName, std::string("factor")); + types.push_back(overload->parameters[0].type.spelling); + } + std::sort(types.begin(), types.end()); + CHECK_EQ(llvm::join(types, ","), std::string("Double,Int")); +} + +TEST(ParameterLabels) { + const Symbol* describe = symbolAt(demo(), "Polygon.describe(_:)"); + REQUIRE(describe && describe->parameters.size() == 1); + CHECK_EQ(describe->parameters[0].label, std::string()); + CHECK_EQ(describe->parameters[0].internalName, std::string("polygon")); + CHECK_EQ(describe->parameters[0].type.spelling, std::string("Polygon?")); + CHECK(describe->isStatic); + + const Symbol* fetch = symbolAt(demo(), "Loader.fetch(url:)"); + REQUIRE(fetch && fetch->parameters.size() == 1); + CHECK_EQ(fetch->parameters[0].label, std::string("url")); + CHECK_EQ(fetch->parameters[0].internalName, std::string("url")); + REQUIRE(fetch->parameters[0].type.fragments.size() == 1); + CHECK_EQ(fetch->parameters[0].type.fragments[0].preciseIdentifier, + std::string("s:10Foundation3URLV")); + + const Symbol* plus = symbolAt(demo(), "Ring.+(_:_:)"); + REQUIRE(plus && plus->parameters.size() == 2); + CHECK(plus->kind == SymbolKind::Operator); + CHECK(plus->isStatic); + CHECK_EQ(plus->parameters[1].internalName, std::string("rhs")); + CHECK_EQ(plus->returnType->spelling, std::string("Ring")); +} + +TEST(Effects) { + const Symbol* fetch = symbolAt(demo(), "Loader.fetch(url:)"); + REQUIRE(fetch); + CHECK(fetch->isAsync); + CHECK(fetch->isThrowing); + CHECK_EQ(fetch->returnType->spelling, std::string("String")); + + const Symbol* load = symbolAt(demo(), "Loader.load(path:)"); + REQUIRE(load); + CHECK(!load->isAsync); + CHECK(load->isThrowing); + + const Symbol* wait = symbolAt(demo(), "Loader.wait(seconds:)"); + REQUIRE(wait); + CHECK(wait->isAsync); + CHECK(!wait->isThrowing); + CHECK(!wait->returnType); +} + +TEST(EffectsInsideClosureTypesDoNotLeak) { + // The synthesized actor method takes an `async throws(E)` closure; only the + // method's own effects may be recorded. + for (const Symbol* symbol : + symbolsAt(demo(), "Counter.withSerialExecutor(_:)")) { + REQUIRE(symbol->parameters.size() == 1); + CHECK(symbol->isThrowing); + CHECK_EQ(symbol->thrownType.spelling, std::string("E")); + CHECK_EQ(symbol->returnType->spelling, std::string("T")); + CHECK(symbol->isSynthesized); + } +} + +TEST(Properties) { + const Symbol* x = symbolAt(demo(), "Point.x"); + REQUIRE(x && x->valueType); + CHECK_EQ(x->valueType->spelling, std::string("Double")); + CHECK(x->isSettable); + + const Symbol* vertexCount = symbolAt(demo(), "Polygon.vertexCount"); + REQUIRE(vertexCount); + CHECK(!vertexCount->isSettable); + + const Symbol* name = symbolAt(demo(), "Polygon.name"); + REQUIRE(name); + CHECK(name->isLet); + CHECK(!name->isSettable); + + const Symbol* shared = symbolAt(demo(), "Polygon.shared"); + REQUIRE(shared && shared->valueType); + CHECK(shared->isStatic); + CHECK_EQ(shared->valueType->spelling, std::string("Polygon")); + + const Symbol* area = symbolAt(demo(), "Shape.area"); + REQUIRE(area); + CHECK(area->isProtocolRequirement); + CHECK(!area->isSettable); + + const Symbol* globalCounter = symbolAt(demo(), "globalCounter"); + REQUIRE(globalCounter); + CHECK(globalCounter->kind == SymbolKind::Variable); + CHECK(globalCounter->isSettable); +} + +TEST(Subscripts) { + const Symbol* subscript = symbolAt(demo(), "Polygon.subscript(_:)"); + REQUIRE(subscript && subscript->valueType); + CHECK(subscript->kind == SymbolKind::InstanceSubscript); + CHECK_EQ(subscript->valueType->spelling, std::string("Point")); + CHECK(!subscript->isSettable); + REQUIRE(subscript->parameters.size() == 1); + CHECK_EQ(subscript->parameters[0].label, std::string()); + CHECK_EQ(subscript->parameters[0].internalName, std::string("index")); +} + +TEST(Initializers) { + const Symbol* failable = symbolAt(demo(), "Polygon.init(name:)"); + REQUIRE(failable); + CHECK(failable->isFailable); + CHECK(contains(failable->modifiers, "convenience")); + + const Symbol* designated = + symbolAt(demo(), "Polygon.init(name:vertexCount:)"); + REQUIRE(designated); + CHECK(!designated->isFailable); + CHECK_EQ(designated->parameters.size(), size_t(2)); + + const Symbol* rawValue = symbolAt(demo(), "Flavor.init(rawValue:)"); + REQUIRE(rawValue); + CHECK(rawValue->isFailable); + CHECK_EQ(rawValue->parameters[0].type.spelling, std::string("Int")); +} + +TEST(EnumCases) { + const Symbol* area = symbolAt(demo(), "Measurement.area(width:height:)"); + REQUIRE(area && area->parameters.size() == 2); + CHECK(area->kind == SymbolKind::EnumCase); + CHECK_EQ(area->parameters[0].label, std::string("width")); + CHECK_EQ(area->parameters[1].type.spelling, std::string("Double")); + + const Symbol* length = symbolAt(demo(), "Measurement.length(_:)"); + REQUIRE(length && length->parameters.size() == 1); + CHECK_EQ(length->parameters[0].label, std::string()); + + const Symbol* none = symbolAt(demo(), "Measurement.none"); + REQUIRE(none); + CHECK(none->parameters.empty()); + + const Symbol* flavor = symbolAt(demo(), "Flavor"); + REQUIRE(flavor); + auto names = memberNames(demo(), *flavor); + CHECK(contains(names, "vanilla")); + CHECK(contains(names, "chocolate")); +} + +TEST(NestedTypes) { + const Symbol* unit = symbolAt(demo(), "Measurement.Unit"); + const Symbol* measurement = symbolAt(demo(), "Measurement"); + REQUIRE(unit && measurement); + CHECK(unit->kind == SymbolKind::Struct); + CHECK_EQ(unit->parentId, measurement->preciseId); + CHECK(!contains(demo().topLevelIds, unit->preciseId)); +} + +TEST(ParameterModifiersAndAttributes) { + const Symbol* update = symbolAt(demo(), "Loader.update(_:)"); + REQUIRE(update && update->parameters.size() == 1); + CHECK_EQ(update->parameters[0].modifier, std::string("inout")); + CHECK_EQ(update->parameters[0].type.spelling, std::string("Point")); + + const Symbol* completion = symbolAt(demo(), "Loader.withCompletion(_:)"); + REQUIRE(completion && completion->parameters.size() == 1); + CHECK(contains(completion->parameters[0].attributes, "@escaping")); + CHECK_EQ(completion->parameters[0].type.spelling, + std::string("(Result) -> Void")); + + const Symbol* each = symbolAt(demo(), "Loader.each(_:)"); + REQUIRE(each && each->parameters.size() == 1); + CHECK(each->parameters[0].attributes.empty()); + + for (const Symbol* symbol : + symbolsAt(demo(), "Counter.preconditionIsolated(_:file:line:)")) { + REQUIRE(symbol->parameters.size() == 3); + CHECK(contains(symbol->parameters[0].attributes, "@autoclosure")); + CHECK_EQ(symbol->parameters[0].defaultValue, std::string("String()")); + CHECK_EQ(symbol->parameters[1].defaultValue, std::string("#fileID")); + } +} + +TEST(Generics) { + const Symbol* transform = symbolAt(demo(), "Loader.transform(_:)"); + REQUIRE(transform); + REQUIRE(transform->genericParameters.size() == 1); + CHECK_EQ(transform->genericParameters[0].name, std::string("T")); + REQUIRE(transform->genericConstraints.size() == 1); + CHECK_EQ(transform->genericConstraints[0].kind, std::string("conformance")); + CHECK_EQ(transform->genericConstraints[0].rhs, std::string("Shape")); + CHECK_EQ(transform->returnType->spelling, std::string("T")); +} + +TEST(ActorIsolation) { + const Symbol* canvas = symbolAt(demo(), "Canvas"); + REQUIRE(canvas); + CHECK(contains(canvas->attributes, "@MainActor")); + CHECK(contains(canvas->modifiers, "final")); + + const Symbol* label = symbolAt(demo(), "Counter.label()"); + REQUIRE(label); + CHECK(contains(label->attributes, "nonisolated")); + + const Symbol* increment = symbolAt(demo(), "Counter.increment()"); + REQUIRE(increment); + CHECK(increment->attributes.empty()); +} + +TEST(InheritanceConformanceAndOverrides) { + const Symbol* square = symbolAt(demo(), "Square"); + const Symbol* polygon = symbolAt(demo(), "Polygon"); + const Symbol* shape = symbolAt(demo(), "Shape"); + const Symbol* greeter = symbolAt(demo(), "Greeter"); + REQUIRE(square && polygon && shape && greeter); + CHECK_EQ(square->superclassId, polygon->preciseId); + CHECK(contains(square->conformances, shape->preciseId)); + CHECK(contains(shape->conformances, greeter->preciseId)); + + const Symbol* override = nullptr; + for (const Symbol* candidate : symbolsAt(demo(), "Square.scale(by:)")) { + override = candidate; + } + REQUIRE(override); + CHECK(contains(override->modifiers, "override")); + REQUIRE(!override->overriddenId.empty()); + const Symbol* base = demo().find(override->overriddenId); + REQUIRE(base); + CHECK_EQ(base->parameters[0].type.spelling, std::string("Double")); + + const Symbol* point = symbolAt(demo(), "Point"); + REQUIRE(point); + CHECK(contains(point->conformances, "s:s23CustomStringConvertibleP")); + CHECK_EQ(demo().externalNames.at("s:s23CustomStringConvertibleP"), + std::string("Swift.CustomStringConvertible")); +} + +TEST(ProtocolRequirementsAndWitnesses) { + const Symbol* greeter = symbolAt(demo(), "Greeter"); + REQUIRE(greeter); + auto names = memberNames(demo(), *greeter); + CHECK_EQ(llvm::join(names, ","), std::string("greet(name:)")); + + const Symbol* requirement = symbolAt(demo(), "Greeter.greet(name:)"); + const Symbol* witness = symbolAt(demo(), "Demo.greet(name:)"); + REQUIRE(requirement && witness); + CHECK(requirement->isProtocolRequirement); + CHECK(!witness->isProtocolRequirement); + CHECK_EQ(witness->sourceOriginId, requirement->preciseId); +} + +TEST(ExtensionsOfExternalTypes) { + auto it = demo().externalTypes.find("s:SS"); + REQUIRE(it != demo().externalTypes.end()); + const ExternalType& string = it->second; + CHECK_EQ(string.qualifiedName, std::string("Swift.String")); + CHECK_EQ(string.extendedModule, std::string("Swift")); + CHECK_EQ(string.typeKind, std::string("swift.struct")); + REQUIRE(string.memberIds.size() == 1); + const Symbol* shouted = demo().find(string.memberIds[0]); + REQUIRE(shouted); + CHECK_EQ(shouted->name, std::string("shouted")); + CHECK_EQ(shouted->sourceGraph, std::string("SwiftDemo@Swift.symbols.json")); + CHECK(!contains(demo().topLevelIds, shouted->preciseId)); + + auto array = demo().externalTypes.find("s:Sa"); + REQUIRE(array != demo().externalTypes.end()); + REQUIRE(array->second.memberIds.size() == 1); + const Symbol* centroid = demo().find(array->second.memberIds[0]); + REQUIRE(centroid && centroid->extension); + REQUIRE(centroid->extension->constraints.size() == 1); + CHECK_EQ(centroid->extension->constraints[0].kind, std::string("sameType")); + CHECK_EQ(centroid->extension->constraints[0].rhs, std::string("Point")); +} + +TEST(Availability) { + const Symbol* modern = symbolAt(demo(), "Loader.modernOnly()"); + REQUIRE(modern && modern->availability.size() == 1); + CHECK_EQ(modern->availability[0].domain, std::string("iOS")); + REQUIRE(modern->availability[0].introduced); + CHECK_EQ(modern->availability[0].introduced->major, 16); + + const Symbol* legacy = symbolAt(demo(), "Loader.legacyFetch()"); + REQUIRE(legacy && legacy->availability.size() == 1); + CHECK_EQ(legacy->availability[0].domain, std::string("*")); + CHECK(legacy->availability[0].isUnconditionallyDeprecated); + CHECK_EQ(legacy->availability[0].message, + std::string("Use fetch(url:) instead")); + + const Symbol* old = symbolAt(demo(), "Loader.oldFetch()"); + REQUIRE(old && old->availability.size() == 1); + REQUIRE(old->availability[0].deprecated); + CHECK_EQ(old->availability[0].deprecated->major, 17); + CHECK_EQ(old->availability[0].renamed, std::string("fetch(url:)")); +} + +TEST(SynthesizedMembers) { + const Symbol* hashValue = symbolAt(demo(), "Flavor.hashValue"); + REQUIRE(hashValue); + CHECK(hashValue->isSynthesized); + CHECK(!hashValue->location); + CHECK(!hashValue->sourceOriginId.empty()); + + const Symbol* greet = symbolAt(demo(), "Demo.greet(name:)"); + REQUIRE(greet); + CHECK(!greet->isSynthesized); +} + +TEST(NonPublicDeclarationsAreAbsent) { + CHECK(symbolsAt(demo(), "Polygon.hiddenHelper()").empty()); +} + +TEST(TypeAliases) { + const Symbol* alias = symbolAt(demo(), "Coordinates"); + REQUIRE(alias && alias->aliasedType); + CHECK_EQ(alias->aliasedType->spelling, + std::string("(latitude: Double, longitude: Double)")); +} + +TEST(IRSnapshot) { checkSnapshot("SwiftDemo.ir.json", dumpModuleJSON(demo())); } + +TEST(TypeScriptSnapshot) { + Classification classification = classify(demo()); + TypeScript::SwiftDefinitionWriter writer(demo(), classification); + checkSnapshot("swift!SwiftDemo.d.ts", writer.write()); +} + +TEST(LoadOrderDoesNotChangeTheIR) { + std::vector diagnostics; + auto files = + SymbolGraphLoader::findGraphFiles(SWIFT_FIXTURE_GRAPHS_DIR, diagnostics); + REQUIRE(files.size() == 2); + + SymbolGraphLoader reversed; + for (auto it = files.rbegin(); it != files.rend(); ++it) { + reversed.addFile(*it, llvm::sys::path::filename(*it).str()); + } + ModuleSet set = reversed.finish(); + REQUIRE(set.modules.count("SwiftDemo")); + CHECK(dumpModuleJSON(set.modules.at("SwiftDemo")) == dumpModuleJSON(demo())); +} + +TEST(InvalidJSONIsAnError) { + ModuleSet set = loadBuffers({{"broken.symbols.json", "{\"metadata\": "}}); + CHECK(set.hasErrors()); + CHECK(set.modules.empty()); + REQUIRE(set.diagnostics.size() == 1); + CHECK_EQ(set.diagnostics[0].code, std::string("invalid-json")); + CHECK_EQ(set.diagnostics[0].file, std::string("broken.symbols.json")); +} + +TEST(UnsupportedFormatMajorIsRejected) { + ModuleSet set = + loadBuffers({{"future.symbols.json", graphJSON("", "", "1.0.0")}}); + CHECK(set.hasErrors()); + CHECK(set.modules.empty()); + CHECK_EQ(set.diagnostics[0].code, std::string("unsupported-format-version")); +} + +TEST(NewerFormatMinorLoadsWithWarning) { + ModuleSet set = + loadBuffers({{"newer.symbols.json", graphJSON("", "", "0.9.0")}}); + CHECK(!set.hasErrors()); + CHECK_EQ(set.modules.count("Mini"), size_t(1)); + REQUIRE(set.diagnostics.size() == 1); + CHECK_EQ(set.diagnostics[0].code, std::string("newer-format-version")); +} + +TEST(UnknownKindsAreReportedAndKept) { + std::string symbol = + symbolJSON("s:4Mini1xv", "swift.newfangled", "x", + R"({"kind":"keyword","spelling":"newfangled"})"); + ModuleSet set = loadBuffers({{"mini.symbols.json", graphJSON(symbol, "")}}); + REQUIRE(set.modules.count("Mini")); + const Symbol* x = set.modules.at("Mini").find("s:4Mini1xv"); + REQUIRE(x); + CHECK(x->kind == SymbolKind::Unknown); + CHECK_EQ(x->kindIdentifier, std::string("swift.newfangled")); + bool reported = false; + for (const auto& diagnostic : set.diagnostics) { + reported |= diagnostic.code == "unknown-symbol-kind" && + diagnostic.symbolId == "s:4Mini1xv"; + } + CHECK(reported); +} + +TEST(DanglingRelationshipsAreReported) { + ModuleSet set = loadBuffers( + {{"mini.symbols.json", + graphJSON( + "", + R"({"kind":"memberOf","source":"s:missing","target":"s:alsoMissing"})")}}); + REQUIRE(set.diagnostics.size() == 1); + CHECK_EQ(set.diagnostics[0].code, std::string("dangling-relationship")); + CHECK(!set.hasErrors()); +} + +TEST(ConflictingDuplicateSymbolsAreReported) { + std::string first = symbolJSON( + "s:4Mini1fyyF", "swift.func", "f()", + R"json({"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"f"},{"kind":"text","spelling":"()"})json"); + std::string second = symbolJSON( + "s:4Mini1fyyF", "swift.func", "f()", + R"json({"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"f"},{"kind":"text","spelling":"() async"})json"); + ModuleSet set = loadBuffers({{"a.symbols.json", graphJSON(first, "")}, + {"b.symbols.json", graphJSON(second, "")}}); + REQUIRE(set.modules.count("Mini")); + CHECK_EQ(set.modules.at("Mini").symbols.size(), size_t(1)); + CHECK_EQ(set.modules.at("Mini").find("s:4Mini1fyyF")->sourceGraph, + std::string("a.symbols.json")); + REQUIRE(set.diagnostics.size() == 1); + CHECK_EQ(set.diagnostics[0].code, std::string("duplicate-symbol")); + + ModuleSet identical = loadBuffers({{"a.symbols.json", graphJSON(first, "")}, + {"b.symbols.json", graphJSON(first, "")}}); + CHECK(identical.diagnostics.empty()); +} + +TEST(AsyncImportVariantsAreBothKept) { + // Swift imports an Objective-C completion-handler method twice under one + // USR: as written and as an `async` variant. + std::string usr = "c:objc(cs)Mini(im)loadWithCompletion:"; + std::string type = symbolJSON( + "c:objc(cs)Mini", "swift.class", "Mini", + R"json({"kind":"keyword","spelling":"class"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"Mini"})json"); + std::string callback = symbolJSON( + usr, "swift.method", "load(completion:)", + R"json({"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"load"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"completion"},{"kind":"text","spelling":": "},{"kind":"attribute","spelling":"@escaping"},{"kind":"text","spelling":" () -> "},{"kind":"typeIdentifier","spelling":"Void"},{"kind":"text","spelling":")"})json", + "Mini"); + std::string async = symbolJSON( + usr, "swift.method", "load()", + R"json({"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"load"},{"kind":"text","spelling":"() "},{"kind":"keyword","spelling":"async"})json", + "Mini"); + std::string relationship = R"({"kind":"memberOf","source":")" + usr + + R"(","target":"c:objc(cs)Mini"})"; + + for (bool asyncFirst : {false, true}) { + std::string symbols = + type + "," + + (asyncFirst ? async + "," + callback : callback + "," + async); + ModuleSet set = + loadBuffers({{"mini.symbols.json", graphJSON(symbols, relationship)}}); + CHECK_EQ(diagnosticCodes(set.diagnostics), std::string()); + REQUIRE(set.modules.count("Mini")); + const Module& module = set.modules.at("Mini"); + const Symbol* original = module.find(usr); + const Symbol* variant = module.find(usr + "#async"); + REQUIRE(original && variant); + CHECK(!original->isAsync); + CHECK(variant->isAsync); + CHECK_EQ(variant->usr, usr); + CHECK_EQ(variant->name, std::string("load()")); + CHECK_EQ(memberNames(module, *module.find("c:objc(cs)Mini")).size(), + size_t(2)); + } +} + +TEST(SubclassRedeclarationsAreKeyedByOwner) { + // NSMutableArray redeclares NSArray's subscript (adding a setter) under the + // same USR. + std::string usr = "c:objc(cs)NSArray(im)objectAtIndexedSubscript:"; + auto type = [](const std::string& name) { + return symbolJSON( + "c:objc(cs)" + name, "swift.class", name, + R"json({"kind":"keyword","spelling":"class"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":")json" + + name + R"json("})json"); + }; + auto subscript = [&](const std::string& owner, const std::string& accessors) { + return symbolJSON( + usr, "swift.subscript", "subscript(_:)", + R"json({"kind":"keyword","spelling":"subscript"},{"kind":"text","spelling":"("},{"kind":"internalParam","spelling":"idx"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int"},{"kind":"text","spelling":") -> "},{"kind":"keyword","spelling":"Any"},{"kind":"text","spelling":" { "},)json" + + accessors + R"json({"kind":"text","spelling":" }"})json", + owner); + }; + std::string base = + subscript("NSArray", R"json({"kind":"keyword","spelling":"get"},)json"); + std::string mutableVariant = subscript( + "NSMutableArray", + R"json({"kind":"keyword","spelling":"get"},{"kind":"text","spelling":" "},{"kind":"keyword","spelling":"set"},)json"); + std::string relationships = + R"({"kind":"memberOf","source":")" + usr + + R"(","target":"c:objc(cs)NSArray"},{"kind":"memberOf","source":")" + usr + + R"(","target":"c:objc(cs)NSMutableArray"})"; + + for (bool mutableFirst : {false, true}) { + std::string symbols = type("NSArray") + "," + type("NSMutableArray") + "," + + (mutableFirst ? mutableVariant + "," + base + : base + "," + mutableVariant); + ModuleSet set = + loadBuffers({{"mini.symbols.json", graphJSON(symbols, relationships)}}); + CHECK_EQ(diagnosticCodes(set.diagnostics), std::string()); + REQUIRE(set.modules.count("Mini")); + const Module& module = set.modules.at("Mini"); + const Symbol* plain = module.find(usr); + const Symbol* owned = module.find(usr + "#NSMutableArray"); + REQUIRE(plain && owned); + CHECK(!plain->isSettable); + CHECK(owned->isSettable); + CHECK_EQ(plain->parentId, std::string("c:objc(cs)NSArray")); + CHECK_EQ(owned->parentId, std::string("c:objc(cs)NSMutableArray")); + CHECK_EQ(module.find("c:objc(cs)NSArray")->memberIds.size(), size_t(1)); + CHECK_EQ(module.find("c:objc(cs)NSMutableArray")->memberIds.size(), + size_t(1)); + } +} + +TEST(ExternalConformancesAreRecorded) { + std::string relationship = + R"({"kind":"conformsTo","source":"s:Sa","target":"s:4Mini1PP"},)" + R"({"kind":"memberOf","source":"s:4Mini1fyyF","target":"s:Sa","targetFallback":"Swift.Array"})"; + std::string member = symbolJSON( + "s:4Mini1fyyF", "swift.method", "f()", + R"json({"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"f"},{"kind":"text","spelling":"()"})json"); + ModuleSet set = + loadBuffers({{"mini.symbols.json", graphJSON(member, relationship)}}); + CHECK_EQ(diagnosticCodes(set.diagnostics), std::string()); + REQUIRE(set.modules.count("Mini")); + const auto& externals = set.modules.at("Mini").externalTypes; + REQUIRE(externals.count("s:Sa")); + CHECK_EQ(externals.at("s:Sa").qualifiedName, std::string("Swift.Array")); + CHECK_EQ(llvm::join(externals.at("s:Sa").conformances, ","), + std::string("s:4Mini1PP")); +} + +TEST(SkimmerHandlesStringsAndNesting) { + // Braces, brackets and escaped quotes inside strings must not affect the + // structural scan. + std::string symbol = symbolJSON( + "s:4Mini1fyyF", "swift.func", "f()", + R"json({"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"f"},{"kind":"text","spelling":"()"})json"); + symbol.insert( + symbol.size() - 1, + R"json(,"docComment":{"lines":[{"text":"a } ] { [ \"quoted\" \\"}]})json"); + ModuleSet set = loadBuffers({{"mini.symbols.json", graphJSON(symbol, "")}}); + CHECK_EQ(diagnosticCodes(set.diagnostics), std::string()); + REQUIRE(set.modules.count("Mini")); + const Symbol* f = set.modules.at("Mini").find("s:4Mini1fyyF"); + REQUIRE(f); + CHECK_EQ(f->docComment, std::string("a } ] { [ \"quoted\" \\")); + + ModuleSet trailing = + loadBuffers({{"mini.symbols.json", graphJSON(symbol, "") + " {}"}}); + CHECK(trailing.hasErrors()); + CHECK_EQ(trailing.diagnostics[0].code, std::string("invalid-json")); +} + +TEST(LabelMismatchesAreReported) { + // Name claims a labeled argument the declaration does not have. + std::string symbol = symbolJSON( + "s:4Mini1fyySiF", "swift.func", "f(value:)", + R"json({"kind":"keyword","spelling":"func"},{"kind":"text","spelling":" "},{"kind":"identifier","spelling":"f"},{"kind":"text","spelling":"("},{"kind":"externalParam","spelling":"_"},{"kind":"text","spelling":" "},{"kind":"internalParam","spelling":"value"},{"kind":"text","spelling":": "},{"kind":"typeIdentifier","spelling":"Int"},{"kind":"text","spelling":")"})json"); + ModuleSet set = loadBuffers({{"mini.symbols.json", graphJSON(symbol, "")}}); + REQUIRE(set.diagnostics.size() == 1); + CHECK_EQ(set.diagnostics[0].code, std::string("parameter-label-mismatch")); +} + +TEST(MissingDirectoryIsAnError) { + ModuleSet set = + loadSymbolGraphDirectory(SWIFT_FIXTURE_GRAPHS_DIR "/does-not-exist"); + CHECK(set.hasErrors()); + CHECK_EQ(set.diagnostics[0].code, std::string("missing-directory")); +} diff --git a/metadata-generator/tests/swift/TestHarness.h b/metadata-generator/tests/swift/TestHarness.h new file mode 100644 index 000000000..60c93b5ab --- /dev/null +++ b/metadata-generator/tests/swift/TestHarness.h @@ -0,0 +1,94 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace TestHarness { + +struct TestCase { + const char* name; + std::function body; +}; + +inline std::vector& registry() { + static std::vector tests; + return tests; +} + +inline int& failureCount() { + static int failures = 0; + return failures; +} + +struct Registrar { + Registrar(const char* name, std::function body) { + registry().push_back(TestCase{name, std::move(body)}); + } +}; + +inline void fail(const char* file, int line, const std::string& message) { + failureCount()++; + std::cerr << file << ":" << line << ": FAILED: " << message << std::endl; +} + +// Runs every registered test whose name contains `filter`. +inline int runAll(const std::string& filter) { + int ran = 0; + for (const auto& test : registry()) { + if (!filter.empty() && + std::string(test.name).find(filter) == std::string::npos) { + continue; + } + int before = failureCount(); + test.body(); + ran++; + std::cout << (failureCount() == before ? "[ OK ] " : "[FAIL] ") << test.name + << std::endl; + } + std::cout << ran << " tests, " << failureCount() << " failed checks" + << std::endl; + return failureCount() == 0 && ran > 0 ? 0 : 1; +} + +} // namespace TestHarness + +#define TEST_CONCAT_INNER(a, b) a##b +#define TEST_CONCAT(a, b) TEST_CONCAT_INNER(a, b) + +#define TEST(name) \ + static void TEST_CONCAT(test_, name)(); \ + static TestHarness::Registrar TEST_CONCAT(registrar_, name)( \ + #name, TEST_CONCAT(test_, name)); \ + static void TEST_CONCAT(test_, name)() + +#define CHECK(condition) \ + do { \ + if (!(condition)) { \ + TestHarness::fail(__FILE__, __LINE__, "CHECK(" #condition ")"); \ + } \ + } while (0) + +#define CHECK_EQ(actual, expected) \ + do { \ + const auto& actualValue = (actual); \ + const auto& expectedValue = (expected); \ + if (!(actualValue == expectedValue)) { \ + std::ostringstream message; \ + message << #actual << " == " << #expected \ + << "\n actual: " << actualValue \ + << "\n expected: " << expectedValue; \ + TestHarness::fail(__FILE__, __LINE__, message.str()); \ + } \ + } while (0) + +// Stops the current test when a precondition for later checks fails. +#define REQUIRE(condition) \ + do { \ + if (!(condition)) { \ + TestHarness::fail(__FILE__, __LINE__, "REQUIRE(" #condition ")"); \ + return; \ + } \ + } while (0) diff --git a/metadata-generator/tests/swift/TestMain.cpp b/metadata-generator/tests/swift/TestMain.cpp new file mode 100644 index 000000000..703df7888 --- /dev/null +++ b/metadata-generator/tests/swift/TestMain.cpp @@ -0,0 +1,5 @@ +#include "TestHarness.h" + +int main(int argc, char** argv) { + return TestHarness::runAll(argc > 1 ? argv[1] : ""); +} diff --git a/metadata-generator/tests/swift/TestSupport.h b/metadata-generator/tests/swift/TestSupport.h new file mode 100644 index 000000000..29da1b0c0 --- /dev/null +++ b/metadata-generator/tests/swift/TestSupport.h @@ -0,0 +1,109 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "Swift/SymbolGraphLoader.h" +#include "TestHarness.h" + +namespace TestSupport { + +using namespace Swift; + +inline const ModuleSet& fixture() { + static ModuleSet set = loadSymbolGraphDirectory(SWIFT_FIXTURE_GRAPHS_DIR); + return set; +} + +inline const Module& demo() { + static const Module empty; + auto it = fixture().modules.find("SwiftDemo"); + return it == fixture().modules.end() ? empty : it->second; +} + +inline std::vector symbolsAt(const Module& module, + const std::string& path) { + std::vector result; + for (const auto& entry : module.symbols) { + if (llvm::join(entry.second.pathComponents, ".") == path) { + result.push_back(&entry.second); + } + } + return result; +} + +inline const Symbol* symbolAt(const Module& module, const std::string& path) { + auto symbols = symbolsAt(module, path); + return symbols.size() == 1 ? symbols.front() : nullptr; +} + +inline std::vector memberNames(const Module& module, + const Symbol& symbol) { + std::vector names; + for (const auto& id : symbol.memberIds) { + if (const Symbol* member = module.find(id)) { + names.push_back(member->name); + } + } + return names; +} + +inline bool contains(const std::vector& values, + const std::string& value) { + return std::find(values.begin(), values.end(), value) != values.end(); +} + +inline std::string diagnosticCodes(const std::vector& diagnostics) { + std::vector codes; + for (const auto& diagnostic : diagnostics) { + codes.push_back(diagnostic.code + "(" + diagnostic.message + ")"); + } + return llvm::join(codes, ", "); +} + +// Compares `actual` against the checked-in file at `path`. +// NS_UPDATE_SNAPSHOTS=1 rewrites the file instead. +inline void checkFile(const std::string& path, const std::string& actual) { + if (const char* update = std::getenv("NS_UPDATE_SNAPSHOTS"); + update && *update == '1') { + std::error_code error; + llvm::raw_fd_ostream out(path, error, llvm::sys::fs::OF_Text); + REQUIRE(!error); + out << actual; + return; + } + + auto expected = llvm::MemoryBuffer::getFile(path, /*IsText*/ true); + if (!expected) { + TestHarness::fail( + __FILE__, __LINE__, + "missing snapshot " + path + " (run with NS_UPDATE_SNAPSHOTS=1)"); + return; + } + if ((*expected)->getBuffer() != actual) { + std::string actualPath = path + ".actual"; + std::error_code error; + llvm::raw_fd_ostream out(actualPath, error, llvm::sys::fs::OF_Text); + out << actual; + TestHarness::fail(__FILE__, __LINE__, + "snapshot mismatch: diff " + path + " " + actualPath); + } +} + +// Compares `actual` against tests/swift/snapshots/. +inline void checkSnapshot(const std::string& fileName, + const std::string& actual) { + llvm::SmallString<256> path(SWIFT_SNAPSHOT_DIR); + llvm::sys::path::append(path, fileName); + checkFile(path.str().str(), actual); +} + +} // namespace TestSupport diff --git a/metadata-generator/tests/swift/ThunkEmitterTests.cpp b/metadata-generator/tests/swift/ThunkEmitterTests.cpp new file mode 100644 index 000000000..210e393ae --- /dev/null +++ b/metadata-generator/tests/swift/ThunkEmitterTests.cpp @@ -0,0 +1,133 @@ +#include "Swift/CapabilityClassifier.h" +#include "Swift/ThunkEmitter.h" +#include "SwiftToolchain.h" +#include "TestHarness.h" +#include "TestSupport.h" +#include "TypeScript/SwiftDefinitionWriter.h" + +using namespace Swift; +using namespace TestSupport; + +namespace { + +const ThunkSource& thunks() { + static ThunkSource source = emitThunks(demo(), classify(demo())); + return source; +} + +bool registers(const std::string& line) { + return thunks().source.find(line) != std::string::npos; +} + +} // namespace + +// TestRunner compiles this checked-in copy (TestFixtures/SwiftDemo/Interop), +// so it must be exactly what the generator emits. +TEST(ThunkSourceMatchesFixtureInterop) { + checkFile(SWIFT_FIXTURE_DIR "/Interop/SwiftDemo+NativeScript.swift", + thunks().source); +} + +TEST(ThunksTypeCheck) { + if (fixtureModuleDirectory().empty()) { + std::cout << " (skipped: no Swift toolchain)" << std::endl; + return; + } + std::string errors = + typeCheckAgainstFixture(thunks().source, "-parse-as-library"); + if (!errors.empty()) { + TestHarness::fail(__FILE__, __LINE__, + "thunks failed to type-check:\n" + errors); + } +} + +TEST(ThunkRegistration) { + CHECK_EQ(thunks().registerSymbol, std::string("ns_swift_register_SwiftDemo")); + CHECK_EQ(thunks().fingerprint.size(), size_t(16)); + CHECK(thunks().thunkCount > 0); + CHECK(registers("registerModule(registrar, 1, \"SwiftDemo\", \"" + + thunks().fingerprint + "\", __nsRelease)")); + // Instance method with labels; signature (String, Int) -> String. + CHECK(registers("\"greet\", \"greet(name:times:)\", \"s,i64>s\"")); + // Failable initializer of a class returns an optional object. + CHECK(registers("\"constructor\", \"init(name:)\", \"s>o")); + // Ambiguous overloads carry the flag (4) and stay distinct by signature. + CHECK(registers(", 1, 4, \"scale\", \"scale(by:)\", \"f64>v\"")); + CHECK(registers(", 1, 4, \"scale\", \"scale(by:)\", \"i64>v\"")); + // Enum cases register without a thunk. + CHECK(registers("\"vanilla\", \"vanilla\", \">e")); + // A case named `none` maps to the enum's case, not Optional.none. + CHECK(registers("case \"none\": return SwiftDemo.Precipitation.`none`")); + // Settable stored property registers a setter. + CHECK(registers("\"x\", \"x\", \">f64\", __nsThunk")); +} + +TEST(ThunkFingerprintTracksSurface) { + Classification classification = classify(demo()); + ThunkSource original = emitThunks(demo(), classification); + // Demoting one member changes the registered surface. + std::map rejections = { + {symbolAt(demo(), "Demo.greet(name:)")->preciseId, "test"}}; + ThunkSource reduced = emitThunks(demo(), classify(demo(), rejections)); + CHECK(original.fingerprint != reduced.fingerprint); + CHECK_EQ(emitThunks(demo(), classification).fingerprint, + original.fingerprint); +} + +// The generated declarations, with the runtime's types/ns-swift.d.ts, accept +// the documented usage and reject what the runtime rejects. Needs a `tsc` +// on PATH or in NS_TSC; skipped otherwise. +TEST(TypeScriptUsageCompiles) { + std::string tsc; + if (const char* configured = std::getenv("NS_TSC"); + configured && *configured) { + tsc = configured; + } else if (auto found = llvm::sys::findProgramByName("tsc")) { + tsc = *found; + } else { + std::cout << " (skipped: no tsc; set NS_TSC)" << std::endl; + return; + } + + llvm::SmallString<128> directory; + REQUIRE(!llvm::sys::fs::createUniqueDirectory("swift-tsc", directory)); + auto write = [&](const std::string& name, const std::string& content) { + llvm::SmallString<128> path(directory); + llvm::sys::path::append(path, name); + std::error_code error; + llvm::raw_fd_ostream out(path, error, llvm::sys::fs::OF_Text); + out << content; + return path.str().str(); + }; + Classification classification = classify(demo()); + write("swift-SwiftDemo.d.ts", + TypeScript::SwiftDefinitionWriter(demo(), classification).write()); + auto usage = + llvm::MemoryBuffer::getFile(SWIFT_TEST_DIR "/typescript/usage.ts"); + REQUIRE(usage); + std::string usagePath = + write("usage.ts", "/// \n" + "/// \n" + + (*usage)->getBuffer().str()); + + llvm::SmallString<128> log(directory); + llvm::sys::path::append(log, "tsc.log"); + std::string command = "'" + tsc + + "' --noEmit --strict --target es2022 --module esnext " + "--moduleResolution bundler --lib es2022 '" + + usagePath + "'"; + auto shell = llvm::sys::findProgramByName("sh"); + std::optional redirects[] = { + std::nullopt, llvm::StringRef(log), llvm::StringRef(log)}; + int status = llvm::sys::ExecuteAndWait(*shell, {*shell, "-c", command}, + std::nullopt, redirects); + if (status != 0) { + auto output = llvm::MemoryBuffer::getFile(log); + TestHarness::fail( + __FILE__, __LINE__, + "tsc rejected the declarations:\n" + + (output ? (*output)->getBuffer().str() : std::string())); + } + llvm::sys::fs::remove_directories(directory); +} diff --git a/metadata-generator/tests/swift/snapshots/SwiftDemo.coverage.json b/metadata-generator/tests/swift/snapshots/SwiftDemo.coverage.json new file mode 100644 index 000000000..114155fec --- /dev/null +++ b/metadata-generator/tests/swift/snapshots/SwiftDemo.coverage.json @@ -0,0 +1,1164 @@ +{ + "module": "SwiftDemo", + "totals": { + "declarations": { + "total": 113, + "objc-direct": 0, + "swift-generated": 68, + "swift-specialized": 5, + "type-only": 6, + "unsupported": 34, + "not-applicable": 0 + }, + "callable": { + "total": 96, + "objc-direct": 0, + "swift-generated": 57, + "swift-specialized": 5, + "type-only": 3, + "unsupported": 31, + "not-applicable": 0 + }, + "effectiveCallable": 57, + "compilerVerified": false, + "compiledThunks": null, + "runtimeTested": null + }, + "byKind": { + "actor": { + "total": 1, + "objc-direct": 0, + "swift-generated": 1, + "swift-specialized": 0, + "type-only": 0, + "unsupported": 0, + "not-applicable": 0 + }, + "class": { + "total": 6, + "objc-direct": 0, + "swift-generated": 6, + "swift-specialized": 0, + "type-only": 0, + "unsupported": 0, + "not-applicable": 0 + }, + "enum": { + "total": 4, + "objc-direct": 0, + "swift-generated": 2, + "swift-specialized": 0, + "type-only": 0, + "unsupported": 2, + "not-applicable": 0 + }, + "enumCase": { + "total": 11, + "objc-direct": 0, + "swift-generated": 5, + "swift-specialized": 0, + "type-only": 0, + "unsupported": 6, + "not-applicable": 0 + }, + "function": { + "total": 6, + "objc-direct": 0, + "swift-generated": 6, + "swift-specialized": 0, + "type-only": 0, + "unsupported": 0, + "not-applicable": 0 + }, + "initializer": { + "total": 13, + "objc-direct": 0, + "swift-generated": 11, + "swift-specialized": 0, + "type-only": 0, + "unsupported": 2, + "not-applicable": 0 + }, + "instanceMethod": { + "total": 33, + "objc-direct": 0, + "swift-generated": 13, + "swift-specialized": 5, + "type-only": 1, + "unsupported": 14, + "not-applicable": 0 + }, + "instanceProperty": { + "total": 20, + "objc-direct": 0, + "swift-generated": 14, + "swift-specialized": 0, + "type-only": 1, + "unsupported": 5, + "not-applicable": 0 + }, + "instanceSubscript": { + "total": 1, + "objc-direct": 0, + "swift-generated": 0, + "swift-specialized": 0, + "type-only": 0, + "unsupported": 1, + "not-applicable": 0 + }, + "operator": { + "total": 3, + "objc-direct": 0, + "swift-generated": 0, + "swift-specialized": 0, + "type-only": 0, + "unsupported": 3, + "not-applicable": 0 + }, + "protocol": { + "total": 2, + "objc-direct": 0, + "swift-generated": 0, + "swift-specialized": 0, + "type-only": 2, + "unsupported": 0, + "not-applicable": 0 + }, + "struct": { + "total": 3, + "objc-direct": 0, + "swift-generated": 2, + "swift-specialized": 0, + "type-only": 0, + "unsupported": 1, + "not-applicable": 0 + }, + "typeAlias": { + "total": 1, + "objc-direct": 0, + "swift-generated": 0, + "swift-specialized": 0, + "type-only": 1, + "unsupported": 0, + "not-applicable": 0 + }, + "typeMethod": { + "total": 2, + "objc-direct": 0, + "swift-generated": 2, + "swift-specialized": 0, + "type-only": 0, + "unsupported": 0, + "not-applicable": 0 + }, + "typeProperty": { + "total": 5, + "objc-direct": 0, + "swift-generated": 4, + "swift-specialized": 0, + "type-only": 1, + "unsupported": 0, + "not-applicable": 0 + }, + "variable": { + "total": 2, + "objc-direct": 0, + "swift-generated": 2, + "swift-specialized": 0, + "type-only": 0, + "unsupported": 0, + "not-applicable": 0 + } + }, + "reasons": { + "actor-isolated": 2, + "async": 2, + "closure": 4, + "collection": 1, + "enum-associated-values": 2, + "external-type-extension": 2, + "generic": 5, + "inout-parameter": 3, + "main-actor": 2, + "nested-type": 1, + "operator": 3, + "owner-not-bridged": 10, + "subscript": 1, + "unbridged-type": 3 + }, + "symbols": [ + { + "id": "s:9SwiftDemo0B0C", + "path": "Demo", + "kind": "class", + "tier": "swift-generated", + "location": "file://Sources/SwiftDemo/Demo.swift:5" + }, + { + "id": "s:9SwiftDemo0B0C5greet4name5timesS2S_SitF", + "path": "Demo.greet(name:times:)", + "kind": "instanceMethod", + "tier": "swift-generated", + "jsName": "greet", + "location": "file://Sources/SwiftDemo/Extensions.swift:2" + }, + { + "id": "s:9SwiftDemo0B0C5greet4nameS2S_tF", + "path": "Demo.greet(name:)", + "kind": "instanceMethod", + "tier": "swift-generated", + "jsName": "greet", + "location": "file://Sources/SwiftDemo/Demo.swift:7" + }, + { + "id": "s:9SwiftDemo0B0C7versionSSvpZ", + "path": "Demo.version", + "kind": "typeProperty", + "tier": "swift-generated", + "jsName": "version", + "location": "file://Sources/SwiftDemo/Extensions.swift:6" + }, + { + "id": "s:9SwiftDemo0B0CACycfc", + "path": "Demo.init()", + "kind": "initializer", + "tier": "swift-generated", + "jsName": "constructor", + "location": "file://Sources/SwiftDemo/Demo.swift:6" + }, + { + "id": "s:9SwiftDemo10ShapeErrorO", + "path": "ShapeError", + "kind": "enum", + "tier": "unsupported", + "reasons": [ + "enum-associated-values" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:55" + }, + { + "id": "s:9SwiftDemo10ShapeErrorO11invalidSideyACSdcACmF", + "path": "ShapeError.invalidSide(_:)", + "kind": "enumCase", + "tier": "unsupported", + "reasons": [ + "owner-not-bridged" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:56" + }, + { + "id": "s:9SwiftDemo10ShapeErrorO12tooManySidesyACSi_SitcACmF", + "path": "ShapeError.tooManySides(count:limit:)", + "kind": "enumCase", + "tier": "unsupported", + "reasons": [ + "owner-not-bridged" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:57" + }, + { + "id": "s:9SwiftDemo10ShapeErrorO7unknownyA2CmF", + "path": "ShapeError.unknown", + "kind": "enumCase", + "tier": "unsupported", + "reasons": [ + "owner-not-bridged" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:58" + }, + { + "id": "s:9SwiftDemo10echoUInt64ys0D0VADF", + "path": "echoUInt64(_:)", + "kind": "function", + "tier": "swift-generated", + "jsName": "echoUInt64", + "location": "file://Sources/SwiftDemo/Values.swift:10" + }, + { + "id": "s:9SwiftDemo10largestIntSiyF", + "path": "largestInt()", + "kind": "function", + "tier": "swift-generated", + "jsName": "largestInt", + "location": "file://Sources/SwiftDemo/Values.swift:11" + }, + { + "id": "s:9SwiftDemo11Coordinatesa", + "path": "Coordinates", + "kind": "typeAlias", + "tier": "type-only", + "reasons": [ + "type-alias" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:142" + }, + { + "id": "s:9SwiftDemo11MeasurementO", + "path": "Measurement", + "kind": "enum", + "tier": "unsupported", + "reasons": [ + "enum-associated-values" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:61" + }, + { + "id": "s:9SwiftDemo11MeasurementO4UnitV", + "path": "Measurement.Unit", + "kind": "struct", + "tier": "unsupported", + "reasons": [ + "nested-type" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:66" + }, + { + "id": "s:9SwiftDemo11MeasurementO4UnitV6symbolAESS_tcfc", + "path": "Measurement.Unit.init(symbol:)", + "kind": "initializer", + "tier": "unsupported", + "reasons": [ + "owner-not-bridged" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:68" + }, + { + "id": "s:9SwiftDemo11MeasurementO4UnitV6symbolSSvp", + "path": "Measurement.Unit.symbol", + "kind": "instanceProperty", + "tier": "unsupported", + "reasons": [ + "owner-not-bridged" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:67" + }, + { + "id": "s:9SwiftDemo11MeasurementO4areayACSd_SdtcACmF", + "path": "Measurement.area(width:height:)", + "kind": "enumCase", + "tier": "unsupported", + "reasons": [ + "owner-not-bridged" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:63" + }, + { + "id": "s:9SwiftDemo11MeasurementO4noneyA2CmF", + "path": "Measurement.none", + "kind": "enumCase", + "tier": "unsupported", + "reasons": [ + "owner-not-bridged" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:64" + }, + { + "id": "s:9SwiftDemo11MeasurementO6isNoneSbvp", + "path": "Measurement.isNone", + "kind": "instanceProperty", + "tier": "unsupported", + "reasons": [ + "owner-not-bridged" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:71" + }, + { + "id": "s:9SwiftDemo11MeasurementO6lengthyACSdcACmF", + "path": "Measurement.length(_:)", + "kind": "enumCase", + "tier": "unsupported", + "reasons": [ + "owner-not-bridged" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:62" + }, + { + "id": "s:9SwiftDemo11checkedSideyS2dKF", + "path": "checkedSide(_:)", + "kind": "function", + "tier": "swift-generated", + "jsName": "checkedSide", + "location": "file://Sources/SwiftDemo/Values.swift:4" + }, + { + "id": "s:9SwiftDemo13PrecipitationO", + "path": "Precipitation", + "kind": "enum", + "tier": "swift-generated", + "location": "file://Sources/SwiftDemo/Shapes.swift:51" + }, + { + "id": "s:9SwiftDemo13PrecipitationO4noneyA2CmF", + "path": "Precipitation.none", + "kind": "enumCase", + "tier": "swift-generated", + "jsName": "none", + "location": "file://Sources/SwiftDemo/Shapes.swift:52" + }, + { + "id": "s:9SwiftDemo13PrecipitationO4rainyA2CmF", + "path": "Precipitation.rain", + "kind": "enumCase", + "tier": "swift-generated", + "jsName": "rain", + "location": "file://Sources/SwiftDemo/Shapes.swift:52" + }, + { + "id": "s:9SwiftDemo13PrecipitationO4snowyA2CmF", + "path": "Precipitation.snow", + "kind": "enumCase", + "tier": "swift-generated", + "jsName": "snow", + "location": "file://Sources/SwiftDemo/Shapes.swift:52" + }, + { + "id": "s:9SwiftDemo13PrecipitationO8rawValueACSgSS_tcfc", + "path": "Precipitation.init(rawValue:)", + "kind": "initializer", + "tier": "swift-generated", + "jsName": "constructor" + }, + { + "id": "s:9SwiftDemo13defaultFlavorAA0D0Ovp", + "path": "defaultFlavor", + "kind": "variable", + "tier": "swift-generated", + "jsName": "defaultFlavor", + "location": "file://Sources/SwiftDemo/Shapes.swift:140" + }, + { + "id": "s:9SwiftDemo13globalCounterSivp", + "path": "globalCounter", + "kind": "variable", + "tier": "swift-generated", + "jsName": "globalCounter", + "location": "file://Sources/SwiftDemo/Shapes.swift:141" + }, + { + "id": "s:9SwiftDemo16makeDefaultPointAA0E0VyF", + "path": "makeDefaultPoint()", + "kind": "function", + "tier": "swift-generated", + "jsName": "makeDefaultPoint", + "location": "file://Sources/SwiftDemo/Shapes.swift:139" + }, + { + "id": "s:9SwiftDemo4RingV", + "path": "Ring", + "kind": "struct", + "tier": "swift-generated", + "location": "file://Sources/SwiftDemo/Shapes.swift:77" + }, + { + "id": "s:9SwiftDemo4RingV1poiyA2C_ACtFZ", + "path": "Ring.+(_:_:)", + "kind": "operator", + "tier": "unsupported", + "reasons": [ + "operator" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:91" + }, + { + "id": "s:9SwiftDemo4RingV5inner5outerAcA5PointV_AGtcfc", + "path": "Ring.init(inner:outer:)", + "kind": "initializer", + "tier": "swift-generated", + "jsName": "constructor", + "location": "file://Sources/SwiftDemo/Shapes.swift:81" + }, + { + "id": "s:9SwiftDemo4RingV5innerAA5PointVvp", + "path": "Ring.inner", + "kind": "instanceProperty", + "tier": "swift-generated", + "jsName": "inner", + "location": "file://Sources/SwiftDemo/Shapes.swift:78" + }, + { + "id": "s:9SwiftDemo4RingV5outerAA5PointVvp", + "path": "Ring.outer", + "kind": "instanceProperty", + "tier": "swift-generated", + "jsName": "outer", + "location": "file://Sources/SwiftDemo/Shapes.swift:79" + }, + { + "id": "s:9SwiftDemo4RingV6expand2byySd_tF", + "path": "Ring.expand(by:)", + "kind": "instanceMethod", + "tier": "swift-generated", + "jsName": "expand", + "location": "file://Sources/SwiftDemo/Shapes.swift:86" + }, + { + "id": "s:9SwiftDemo5PointV", + "path": "Point", + "kind": "struct", + "tier": "swift-generated", + "location": "file://Sources/SwiftDemo/Demo.swift:10" + }, + { + "id": "s:9SwiftDemo5PointV11descriptionSSvp", + "path": "Point.description", + "kind": "instanceProperty", + "tier": "swift-generated", + "jsName": "description", + "location": "file://Sources/SwiftDemo/Extensions.swift:10" + }, + { + "id": "s:9SwiftDemo5PointV1x1yACSd_Sdtcfc", + "path": "Point.init(x:y:)", + "kind": "initializer", + "tier": "swift-generated", + "jsName": "constructor", + "location": "file://Sources/SwiftDemo/Demo.swift:13" + }, + { + "id": "s:9SwiftDemo5PointV1xSdvp", + "path": "Point.x", + "kind": "instanceProperty", + "tier": "swift-generated", + "jsName": "x", + "location": "file://Sources/SwiftDemo/Demo.swift:11" + }, + { + "id": "s:9SwiftDemo5PointV1ySdvp", + "path": "Point.y", + "kind": "instanceProperty", + "tier": "swift-generated", + "jsName": "y", + "location": "file://Sources/SwiftDemo/Demo.swift:12" + }, + { + "id": "s:9SwiftDemo5PointV6lengthSdvp", + "path": "Point.length", + "kind": "instanceProperty", + "tier": "swift-generated", + "jsName": "length", + "location": "file://Sources/SwiftDemo/Extensions.swift:11" + }, + { + "id": "s:9SwiftDemo5ShapeP", + "path": "Shape", + "kind": "protocol", + "tier": "type-only", + "reasons": [ + "protocol" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:3" + }, + { + "id": "s:9SwiftDemo5ShapeP4areaSdvp", + "path": "Shape.area", + "kind": "instanceProperty", + "tier": "type-only", + "reasons": [ + "protocol-requirement" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:4" + }, + { + "id": "s:9SwiftDemo5ShapeP5sidesSivpZ", + "path": "Shape.sides", + "kind": "typeProperty", + "tier": "type-only", + "reasons": [ + "protocol-requirement" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:5" + }, + { + "id": "s:9SwiftDemo5shoutySSSgACF", + "path": "shout(_:)", + "kind": "function", + "tier": "swift-generated", + "jsName": "shout", + "location": "file://Sources/SwiftDemo/Values.swift:12" + }, + { + "id": "s:9SwiftDemo6CanvasC", + "path": "Canvas", + "kind": "class", + "tier": "swift-generated", + "location": "file://Sources/SwiftDemo/Shapes.swift:107" + }, + { + "id": "s:9SwiftDemo6CanvasC4drawyyAA5Shape_pF", + "path": "Canvas.draw(_:)", + "kind": "instanceMethod", + "tier": "unsupported", + "reasons": [ + "main-actor" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:109" + }, + { + "id": "s:9SwiftDemo6CanvasCACycfc", + "path": "Canvas.init()", + "kind": "initializer", + "tier": "unsupported", + "reasons": [ + "main-actor" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:108" + }, + { + "id": "s:9SwiftDemo6FlavorO", + "path": "Flavor", + "kind": "enum", + "tier": "swift-generated", + "location": "file://Sources/SwiftDemo/Demo.swift:16" + }, + { + "id": "s:9SwiftDemo6FlavorO11descriptionSSvp", + "path": "Flavor.description", + "kind": "instanceProperty", + "tier": "swift-generated", + "jsName": "description", + "location": "file://Sources/SwiftDemo/Extensions.swift:15" + }, + { + "id": "s:9SwiftDemo6FlavorO7vanillayA2CmF", + "path": "Flavor.vanilla", + "kind": "enumCase", + "tier": "swift-generated", + "jsName": "vanilla", + "location": "file://Sources/SwiftDemo/Demo.swift:16" + }, + { + "id": "s:9SwiftDemo6FlavorO8rawValueACSgSi_tcfc", + "path": "Flavor.init(rawValue:)", + "kind": "initializer", + "tier": "swift-generated", + "jsName": "constructor" + }, + { + "id": "s:9SwiftDemo6FlavorO9chocolateyA2CmF", + "path": "Flavor.chocolate", + "kind": "enumCase", + "tier": "swift-generated", + "jsName": "chocolate", + "location": "file://Sources/SwiftDemo/Demo.swift:16" + }, + { + "id": "s:9SwiftDemo6LoaderC", + "path": "Loader", + "kind": "class", + "tier": "swift-generated", + "location": "file://Sources/SwiftDemo/Shapes.swift:112" + }, + { + "id": "s:9SwiftDemo6LoaderC10modernOnlyyyF", + "path": "Loader.modernOnly()", + "kind": "instanceMethod", + "tier": "swift-generated", + "jsName": "modernOnly", + "location": "file://Sources/SwiftDemo/Shapes.swift:130" + }, + { + "id": "s:9SwiftDemo6LoaderC11legacyFetchyyF", + "path": "Loader.legacyFetch()", + "kind": "instanceMethod", + "tier": "swift-generated", + "jsName": "legacyFetch", + "location": "file://Sources/SwiftDemo/Shapes.swift:133" + }, + { + "id": "s:9SwiftDemo6LoaderC14withCompletionyyys6ResultOySSAA10ShapeErrorOGcF", + "path": "Loader.withCompletion(_:)", + "kind": "instanceMethod", + "tier": "unsupported", + "reasons": [ + "closure" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:122" + }, + { + "id": "s:9SwiftDemo6LoaderC4eachyyySiXEF", + "path": "Loader.each(_:)", + "kind": "instanceMethod", + "tier": "unsupported", + "reasons": [ + "closure" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:123" + }, + { + "id": "s:9SwiftDemo6LoaderC4load4path10Foundation4DataVSS_tKF", + "path": "Loader.load(path:)", + "kind": "instanceMethod", + "tier": "unsupported", + "reasons": [ + "unbridged-type:Foundation.Data" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:115" + }, + { + "id": "s:9SwiftDemo6LoaderC4wait7secondsySd_tYaF", + "path": "Loader.wait(seconds:)", + "kind": "instanceMethod", + "tier": "unsupported", + "reasons": [ + "async" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:117" + }, + { + "id": "s:9SwiftDemo6LoaderC5fetch3urlSS10Foundation3URLV_tYaKF", + "path": "Loader.fetch(url:)", + "kind": "instanceMethod", + "tier": "unsupported", + "reasons": [ + "async" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:116" + }, + { + "id": "s:9SwiftDemo6LoaderC5first2ofxSgSayxG_tlF", + "path": "Loader.first(of:)", + "kind": "instanceMethod", + "tier": "swift-specialized", + "reasons": [ + "generic" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:120" + }, + { + "id": "s:9SwiftDemo6LoaderC6lookup5table3keySiSgSDySSSiG_SStF", + "path": "Loader.lookup(table:key:)", + "kind": "instanceMethod", + "tier": "unsupported", + "reasons": [ + "collection" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:125" + }, + { + "id": "s:9SwiftDemo6LoaderC6updateyyAA5PointVzF", + "path": "Loader.update(_:)", + "kind": "instanceMethod", + "tier": "unsupported", + "reasons": [ + "inout-parameter" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:127" + }, + { + "id": "s:9SwiftDemo6LoaderC8oldFetchyyF", + "path": "Loader.oldFetch()", + "kind": "instanceMethod", + "tier": "swift-generated", + "jsName": "oldFetch", + "location": "file://Sources/SwiftDemo/Shapes.swift:136" + }, + { + "id": "s:9SwiftDemo6LoaderC9transformyxxAA5ShapeRzlF", + "path": "Loader.transform(_:)", + "kind": "instanceMethod", + "tier": "swift-specialized", + "reasons": [ + "generic" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:119" + }, + { + "id": "s:9SwiftDemo6LoaderCACycfc", + "path": "Loader.init()", + "kind": "initializer", + "tier": "swift-generated", + "jsName": "constructor", + "location": "file://Sources/SwiftDemo/Shapes.swift:113" + }, + { + "id": "s:9SwiftDemo6SquareC", + "path": "Square", + "kind": "class", + "tier": "swift-generated", + "location": "file://Sources/SwiftDemo/Shapes.swift:35" + }, + { + "id": "s:9SwiftDemo6SquareC4areaSdvp", + "path": "Square.area", + "kind": "instanceProperty", + "tier": "swift-generated", + "jsName": "area", + "location": "file://Sources/SwiftDemo/Shapes.swift:43" + }, + { + "id": "s:9SwiftDemo6SquareC4sideACSd_tcfc", + "path": "Square.init(side:)", + "kind": "initializer", + "tier": "swift-generated", + "jsName": "constructor", + "location": "file://Sources/SwiftDemo/Shapes.swift:38" + }, + { + "id": "s:9SwiftDemo6SquareC4sideSdvp", + "path": "Square.side", + "kind": "instanceProperty", + "tier": "swift-generated", + "jsName": "side", + "location": "file://Sources/SwiftDemo/Shapes.swift:36" + }, + { + "id": "s:9SwiftDemo6SquareC5greet4nameS2S_tF", + "path": "Square.greet(name:)", + "kind": "instanceMethod", + "tier": "swift-generated", + "jsName": "greet", + "location": "file://Sources/SwiftDemo/Shapes.swift:45" + }, + { + "id": "s:9SwiftDemo6SquareC5scale2byySd_tF", + "path": "Square.scale(by:)", + "kind": "instanceMethod", + "tier": "swift-generated", + "jsName": "scale", + "location": "file://Sources/SwiftDemo/Shapes.swift:47" + }, + { + "id": "s:9SwiftDemo6SquareC5sidesSivpZ", + "path": "Square.sides", + "kind": "typeProperty", + "tier": "swift-generated", + "jsName": "sides", + "location": "file://Sources/SwiftDemo/Shapes.swift:44" + }, + { + "id": "s:9SwiftDemo7CounterC", + "path": "Counter", + "kind": "actor", + "tier": "swift-generated", + "location": "file://Sources/SwiftDemo/Shapes.swift:96" + }, + { + "id": "s:9SwiftDemo7CounterC5labelSSyF", + "path": "Counter.label()", + "kind": "instanceMethod", + "tier": "swift-generated", + "jsName": "label", + "location": "file://Sources/SwiftDemo/Shapes.swift:103" + }, + { + "id": "s:9SwiftDemo7CounterC5valueSivp", + "path": "Counter.value", + "kind": "instanceProperty", + "tier": "unsupported", + "reasons": [ + "actor-isolated" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:97" + }, + { + "id": "s:9SwiftDemo7CounterC9incrementSiyF", + "path": "Counter.increment()", + "kind": "instanceMethod", + "tier": "unsupported", + "reasons": [ + "actor-isolated" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:99" + }, + { + "id": "s:9SwiftDemo7CounterCACycfc", + "path": "Counter.init()", + "kind": "initializer", + "tier": "swift-generated", + "jsName": "constructor", + "location": "file://Sources/SwiftDemo/Shapes.swift:98" + }, + { + "id": "s:9SwiftDemo7GreeterP", + "path": "Greeter", + "kind": "protocol", + "tier": "type-only", + "reasons": [ + "protocol" + ], + "location": "file://Sources/SwiftDemo/Demo.swift:1" + }, + { + "id": "s:9SwiftDemo7GreeterP5greet4nameS2S_tF", + "path": "Greeter.greet(name:)", + "kind": "instanceMethod", + "tier": "type-only", + "reasons": [ + "protocol-requirement" + ], + "location": "file://Sources/SwiftDemo/Demo.swift:2" + }, + { + "id": "s:9SwiftDemo7PolygonC", + "path": "Polygon", + "kind": "class", + "tier": "swift-generated", + "location": "file://Sources/SwiftDemo/Shapes.swift:8" + }, + { + "id": "s:9SwiftDemo7PolygonC11vertexCountSivp", + "path": "Polygon.vertexCount", + "kind": "instanceProperty", + "tier": "swift-generated", + "jsName": "vertexCount", + "location": "file://Sources/SwiftDemo/Shapes.swift:10" + }, + { + "id": "s:9SwiftDemo7PolygonC4makeACyFZ", + "path": "Polygon.make()", + "kind": "typeMethod", + "tier": "swift-generated", + "jsName": "make", + "location": "file://Sources/SwiftDemo/Shapes.swift:27" + }, + { + "id": "s:9SwiftDemo7PolygonC4name11vertexCountACSS_Sitcfc", + "path": "Polygon.init(name:vertexCount:)", + "kind": "initializer", + "tier": "swift-generated", + "jsName": "constructor", + "location": "file://Sources/SwiftDemo/Shapes.swift:13" + }, + { + "id": "s:9SwiftDemo7PolygonC4nameACSgSS_tcfc", + "path": "Polygon.init(name:)", + "kind": "initializer", + "tier": "swift-generated", + "jsName": "constructor", + "location": "file://Sources/SwiftDemo/Shapes.swift:18" + }, + { + "id": "s:9SwiftDemo7PolygonC4nameSSvp", + "path": "Polygon.name", + "kind": "instanceProperty", + "tier": "swift-generated", + "jsName": "name", + "location": "file://Sources/SwiftDemo/Shapes.swift:9" + }, + { + "id": "s:9SwiftDemo7PolygonC5scale1x1yySd_SdtF", + "path": "Polygon.scale(x:y:)", + "kind": "instanceMethod", + "tier": "swift-generated", + "jsName": "scale", + "location": "file://Sources/SwiftDemo/Shapes.swift:25" + }, + { + "id": "s:9SwiftDemo7PolygonC5scale2byySd_tF", + "path": "Polygon.scale(by:)", + "kind": "instanceMethod", + "tier": "swift-generated", + "jsName": "scale", + "ambiguousOverload": true, + "location": "file://Sources/SwiftDemo/Shapes.swift:23" + }, + { + "id": "s:9SwiftDemo7PolygonC5scale2byySi_tF", + "path": "Polygon.scale(by:)", + "kind": "instanceMethod", + "tier": "swift-generated", + "jsName": "scale", + "ambiguousOverload": true, + "location": "file://Sources/SwiftDemo/Shapes.swift:24" + }, + { + "id": "s:9SwiftDemo7PolygonC6sharedACvpZ", + "path": "Polygon.shared", + "kind": "typeProperty", + "tier": "swift-generated", + "jsName": "shared", + "location": "file://Sources/SwiftDemo/Shapes.swift:11" + }, + { + "id": "s:9SwiftDemo7PolygonC8describeySSACSgFZ", + "path": "Polygon.describe(_:)", + "kind": "typeMethod", + "tier": "swift-generated", + "jsName": "describe", + "location": "file://Sources/SwiftDemo/Shapes.swift:28" + }, + { + "id": "s:9SwiftDemo7PolygonCyAA5PointVSicip", + "path": "Polygon.subscript(_:)", + "kind": "instanceSubscript", + "tier": "unsupported", + "reasons": [ + "subscript" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:30" + }, + { + "id": "s:9SwiftDemo7TrackerC", + "path": "Tracker", + "kind": "class", + "tier": "swift-generated", + "location": "file://Sources/SwiftDemo/Values.swift:14" + }, + { + "id": "s:9SwiftDemo7TrackerC2idACSi_tcfc", + "path": "Tracker.init(id:)", + "kind": "initializer", + "tier": "swift-generated", + "jsName": "constructor", + "location": "file://Sources/SwiftDemo/Values.swift:18" + }, + { + "id": "s:9SwiftDemo7TrackerC2idSivp", + "path": "Tracker.id", + "kind": "instanceProperty", + "tier": "swift-generated", + "jsName": "id", + "location": "file://Sources/SwiftDemo/Values.swift:16" + }, + { + "id": "s:9SwiftDemo7TrackerC4sameACyF", + "path": "Tracker.same()", + "kind": "instanceMethod", + "tier": "swift-generated", + "jsName": "same", + "location": "file://Sources/SwiftDemo/Values.swift:25" + }, + { + "id": "s:9SwiftDemo7TrackerC9liveCountSivpZ", + "path": "Tracker.liveCount", + "kind": "typeProperty", + "tier": "swift-generated", + "jsName": "liveCount", + "location": "file://Sources/SwiftDemo/Values.swift:15" + }, + { + "id": "s:9SwiftDemo8echoInt8ys0D0VADF", + "path": "echoInt8(_:)", + "kind": "function", + "tier": "swift-generated", + "jsName": "echoInt8", + "location": "file://Sources/SwiftDemo/Values.swift:9" + }, + { + "id": "s:SQsRi_zRi0_zrlE2neoiySbx_xtFZ::SYNTHESIZED::s:9SwiftDemo13PrecipitationO", + "path": "Precipitation.!=(_:_:)", + "kind": "operator", + "tier": "unsupported", + "reasons": [ + "operator" + ] + }, + { + "id": "s:SQsRi_zRi0_zrlE2neoiySbx_xtFZ::SYNTHESIZED::s:9SwiftDemo6FlavorO", + "path": "Flavor.!=(_:_:)", + "kind": "operator", + "tier": "unsupported", + "reasons": [ + "operator" + ] + }, + { + "id": "s:SS9SwiftDemoE7shoutedSSvp", + "path": "String.shouted", + "kind": "instanceProperty", + "tier": "unsupported", + "reasons": [ + "external-type-extension" + ], + "location": "file://Sources/SwiftDemo/Extensions.swift:19" + }, + { + "id": "s:SYsSHRzSH8RawValueSYRpzrlE04hashB0Sivp::SYNTHESIZED::s:9SwiftDemo13PrecipitationO", + "path": "Precipitation.hashValue", + "kind": "instanceProperty", + "tier": "swift-generated", + "jsName": "hashValue" + }, + { + "id": "s:SYsSHRzSH8RawValueSYRpzrlE04hashB0Sivp::SYNTHESIZED::s:9SwiftDemo6FlavorO", + "path": "Flavor.hashValue", + "kind": "instanceProperty", + "tier": "swift-generated", + "jsName": "hashValue" + }, + { + "id": "s:SYsSHRzSH8RawValueSYRpzrlE4hash4intoys6HasherVz_tF::SYNTHESIZED::s:9SwiftDemo13PrecipitationO", + "path": "Precipitation.hash(into:)", + "kind": "instanceMethod", + "tier": "unsupported", + "reasons": [ + "inout-parameter" + ] + }, + { + "id": "s:SYsSHRzSH8RawValueSYRpzrlE4hash4intoys6HasherVz_tF::SYNTHESIZED::s:9SwiftDemo6FlavorO", + "path": "Flavor.hash(into:)", + "kind": "instanceMethod", + "tier": "unsupported", + "reasons": [ + "inout-parameter" + ] + }, + { + "id": "s:Sa9SwiftDemoAA5PointVRszlE8centroidACyF", + "path": "Array.centroid()", + "kind": "instanceMethod", + "tier": "unsupported", + "reasons": [ + "external-type-extension" + ], + "location": "file://Sources/SwiftDemo/Extensions.swift:23" + }, + { + "id": "s:ScA12_ConcurrencyE14assertIsolated_4file4lineySSyXK_s12StaticStringVSutF::SYNTHESIZED::s:9SwiftDemo7CounterC", + "path": "Counter.assertIsolated(_:file:line:)", + "kind": "instanceMethod", + "tier": "unsupported", + "reasons": [ + "closure", + "unbridged-type:Swift.StaticString" + ] + }, + { + "id": "s:ScA12_ConcurrencyE14assumeIsolated_4file4lineqd__qd__xYiKXE_s12StaticStringVSutKs8SendableRd__lF::SYNTHESIZED::s:9SwiftDemo7CounterC", + "path": "Counter.assumeIsolated(_:file:line:)", + "kind": "instanceMethod", + "tier": "swift-specialized", + "reasons": [ + "generic" + ] + }, + { + "id": "s:ScA12_ConcurrencyE18withSerialExecutoryqd__qd__Scf_pYaqd_0_YKYCXEYaqd_0_YKs5ErrorRd_0_Ri_d__r0_lF::SYNTHESIZED::s:9SwiftDemo7CounterC", + "path": "Counter.withSerialExecutor(_:)", + "kind": "instanceMethod", + "tier": "swift-specialized", + "reasons": [ + "generic" + ] + }, + { + "id": "s:ScA12_ConcurrencyE18withSerialExecutoryqd__qd__Scf_pqd_0_YKXEqd_0_YKs5ErrorRd_0_Ri_d__r0_lF::SYNTHESIZED::s:9SwiftDemo7CounterC", + "path": "Counter.withSerialExecutor(_:)", + "kind": "instanceMethod", + "tier": "swift-specialized", + "reasons": [ + "generic" + ] + }, + { + "id": "s:ScA12_ConcurrencyE20preconditionIsolated_4file4lineySSyXK_s12StaticStringVSutF::SYNTHESIZED::s:9SwiftDemo7CounterC", + "path": "Counter.preconditionIsolated(_:file:line:)", + "kind": "instanceMethod", + "tier": "unsupported", + "reasons": [ + "closure", + "unbridged-type:Swift.StaticString" + ] + }, + { + "id": "s:s5ErrorP10FoundationE20localizedDescriptionSSvp::SYNTHESIZED::s:9SwiftDemo10ShapeErrorO", + "path": "ShapeError.localizedDescription", + "kind": "instanceProperty", + "tier": "unsupported", + "reasons": [ + "owner-not-bridged" + ] + } + ] +} diff --git a/metadata-generator/tests/swift/snapshots/SwiftDemo.ir.json b/metadata-generator/tests/swift/snapshots/SwiftDemo.ir.json new file mode 100644 index 000000000..3f25c0823 --- /dev/null +++ b/metadata-generator/tests/swift/snapshots/SwiftDemo.ir.json @@ -0,0 +1,3071 @@ +{ + "module": "SwiftDemo", + "formatVersion": "0.6.0", + "platform": { + "architecture": "arm64", + "vendor": "apple", + "operatingSystem": "ios", + "environment": "simulator", + "minimumVersion": "15.0.0" + }, + "graphFiles": [ + "SwiftDemo.symbols.json", + "SwiftDemo@Swift.symbols.json" + ], + "topLevel": [ + "s:9SwiftDemo7GreeterP", + "s:9SwiftDemo0B0C", + "s:9SwiftDemo5PointV", + "s:9SwiftDemo6FlavorO", + "s:9SwiftDemo5ShapeP", + "s:9SwiftDemo7PolygonC", + "s:9SwiftDemo6SquareC", + "s:9SwiftDemo13PrecipitationO", + "s:9SwiftDemo10ShapeErrorO", + "s:9SwiftDemo11MeasurementO", + "s:9SwiftDemo4RingV", + "s:9SwiftDemo7CounterC", + "s:9SwiftDemo6CanvasC", + "s:9SwiftDemo6LoaderC", + "s:9SwiftDemo16makeDefaultPointAA0E0VyF", + "s:9SwiftDemo13defaultFlavorAA0D0Ovp", + "s:9SwiftDemo13globalCounterSivp", + "s:9SwiftDemo11Coordinatesa", + "s:9SwiftDemo11checkedSideyS2dKF", + "s:9SwiftDemo8echoInt8ys0D0VADF", + "s:9SwiftDemo10echoUInt64ys0D0VADF", + "s:9SwiftDemo10largestIntSiyF", + "s:9SwiftDemo5shoutySSSgACF", + "s:9SwiftDemo7TrackerC" + ], + "externalTypes": [ + { + "id": "s:SS", + "qualifiedName": "Swift.String", + "extendedModule": "Swift", + "typeKind": "swift.struct", + "members": [ + "s:SS9SwiftDemoE7shoutedSSvp" + ] + }, + { + "id": "s:Sa", + "qualifiedName": "Swift.Array", + "extendedModule": "Swift", + "typeKind": "swift.struct", + "members": [ + "s:Sa9SwiftDemoAA5PointVRszlE8centroidACyF" + ] + } + ], + "externalNames": { + "s:SH": "Swift.Hashable", + "s:SQ": "Swift.Equatable", + "s:SS": "Swift.String", + "s:SY": "Swift.RawRepresentable", + "s:Sa": "Swift.Array", + "s:ScA": "_Concurrency.Actor", + "s:s16SendableMetatypeP": "Swift.SendableMetatype", + "s:s23CustomStringConvertibleP": "Swift.CustomStringConvertible", + "s:s5ErrorP": "Swift.Error", + "s:s8CopyableP": "Swift.Copyable", + "s:s8SendableP": "Swift.Sendable", + "s:s9EscapableP": "Swift.Escapable" + }, + "symbols": [ + { + "id": "s:9SwiftDemo0B0C", + "kind": "class", + "path": "Demo", + "name": "Demo", + "access": "public", + "declaration": "class Demo", + "location": "file://Sources/SwiftDemo/Demo.swift:4:13", + "graph": "SwiftDemo.symbols.json", + "members": [ + "s:9SwiftDemo0B0CACycfc", + "s:9SwiftDemo0B0C5greet4nameS2S_tF", + "s:9SwiftDemo0B0C5greet4name5timesS2S_SitF", + "s:9SwiftDemo0B0C7versionSSvpZ" + ], + "conformances": [ + "s:9SwiftDemo7GreeterP" + ] + }, + { + "id": "s:9SwiftDemo0B0C5greet4name5timesS2S_SitF", + "kind": "instanceMethod", + "path": "Demo.greet(name:times:)", + "name": "greet(name:times:)", + "access": "public", + "declaration": "func greet(name: String, times: Int) -> String", + "parameters": [ + { + "label": "name", + "internalName": "name", + "type": { + "spelling": "String", + "references": [ + "s:SS" + ] + } + }, + { + "label": "times", + "internalName": "times", + "type": { + "spelling": "Int", + "references": [ + "s:Si" + ] + } + } + ], + "returns": { + "spelling": "String", + "references": [ + "s:SS" + ] + }, + "extension": { + "extendedModule": "SwiftDemo", + "typeKind": "swift.class" + }, + "location": "file://Sources/SwiftDemo/Extensions.swift:1:16", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo0B0C" + }, + { + "id": "s:9SwiftDemo0B0C5greet4nameS2S_tF", + "kind": "instanceMethod", + "path": "Demo.greet(name:)", + "name": "greet(name:)", + "access": "public", + "declaration": "func greet(name: String) -> String", + "parameters": [ + { + "label": "name", + "internalName": "name", + "type": { + "spelling": "String", + "references": [ + "s:SS" + ] + } + } + ], + "returns": { + "spelling": "String", + "references": [ + "s:SS" + ] + }, + "location": "file://Sources/SwiftDemo/Demo.swift:6:16", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo0B0C", + "sourceOrigin": "s:9SwiftDemo7GreeterP5greet4nameS2S_tF" + }, + { + "id": "s:9SwiftDemo0B0C7versionSSvpZ", + "kind": "typeProperty", + "path": "Demo.version", + "name": "version", + "access": "public", + "declaration": "static var version: String { get }", + "modifiers": [ + "static" + ], + "static": true, + "valueType": { + "spelling": "String", + "references": [ + "s:SS" + ] + }, + "settable": false, + "extension": { + "extendedModule": "SwiftDemo", + "typeKind": "swift.class" + }, + "location": "file://Sources/SwiftDemo/Extensions.swift:5:22", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo0B0C" + }, + { + "id": "s:9SwiftDemo0B0CACycfc", + "kind": "initializer", + "path": "Demo.init()", + "name": "init()", + "access": "public", + "declaration": "init()", + "location": "file://Sources/SwiftDemo/Demo.swift:5:11", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo0B0C" + }, + { + "id": "s:9SwiftDemo10ShapeErrorO", + "kind": "enum", + "path": "ShapeError", + "name": "ShapeError", + "access": "public", + "declaration": "enum ShapeError", + "location": "file://Sources/SwiftDemo/Shapes.swift:54:12", + "graph": "SwiftDemo.symbols.json", + "members": [ + "s:9SwiftDemo10ShapeErrorO11invalidSideyACSdcACmF", + "s:9SwiftDemo10ShapeErrorO12tooManySidesyACSi_SitcACmF", + "s:9SwiftDemo10ShapeErrorO7unknownyA2CmF", + "s:s5ErrorP10FoundationE20localizedDescriptionSSvp::SYNTHESIZED::s:9SwiftDemo10ShapeErrorO" + ], + "conformances": [ + "s:s16SendableMetatypeP", + "s:s5ErrorP", + "s:s8SendableP" + ] + }, + { + "id": "s:9SwiftDemo10ShapeErrorO11invalidSideyACSdcACmF", + "kind": "enumCase", + "path": "ShapeError.invalidSide(_:)", + "name": "invalidSide(_:)", + "access": "public", + "declaration": "case invalidSide(Double)", + "parameters": [ + { + "type": { + "spelling": "Double", + "references": [ + "s:Sd" + ] + } + } + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:55:9", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo10ShapeErrorO" + }, + { + "id": "s:9SwiftDemo10ShapeErrorO12tooManySidesyACSi_SitcACmF", + "kind": "enumCase", + "path": "ShapeError.tooManySides(count:limit:)", + "name": "tooManySides(count:limit:)", + "access": "public", + "declaration": "case tooManySides(count: Int, limit: Int)", + "parameters": [ + { + "label": "count", + "internalName": "count", + "type": { + "spelling": "Int", + "references": [ + "s:Si" + ] + } + }, + { + "label": "limit", + "internalName": "limit", + "type": { + "spelling": "Int", + "references": [ + "s:Si" + ] + } + } + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:56:9", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo10ShapeErrorO" + }, + { + "id": "s:9SwiftDemo10ShapeErrorO7unknownyA2CmF", + "kind": "enumCase", + "path": "ShapeError.unknown", + "name": "unknown", + "access": "public", + "declaration": "case unknown", + "location": "file://Sources/SwiftDemo/Shapes.swift:57:9", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo10ShapeErrorO" + }, + { + "id": "s:9SwiftDemo10echoUInt64ys0D0VADF", + "kind": "function", + "path": "echoUInt64(_:)", + "name": "echoUInt64(_:)", + "access": "public", + "declaration": "func echoUInt64(_ value: UInt64) -> UInt64", + "parameters": [ + { + "internalName": "value", + "type": { + "spelling": "UInt64", + "references": [ + "s:s6UInt64V" + ] + } + } + ], + "returns": { + "spelling": "UInt64", + "references": [ + "s:s6UInt64V" + ] + }, + "location": "file://Sources/SwiftDemo/Values.swift:9:12", + "graph": "SwiftDemo.symbols.json" + }, + { + "id": "s:9SwiftDemo10largestIntSiyF", + "kind": "function", + "path": "largestInt()", + "name": "largestInt()", + "access": "public", + "declaration": "func largestInt() -> Int", + "returns": { + "spelling": "Int", + "references": [ + "s:Si" + ] + }, + "location": "file://Sources/SwiftDemo/Values.swift:10:12", + "graph": "SwiftDemo.symbols.json" + }, + { + "id": "s:9SwiftDemo11Coordinatesa", + "kind": "typeAlias", + "path": "Coordinates", + "name": "Coordinates", + "access": "public", + "declaration": "typealias Coordinates = (latitude: Double, longitude: Double)", + "aliasedType": { + "spelling": "(latitude: Double, longitude: Double)", + "references": [ + "s:Sd", + "s:Sd" + ] + }, + "location": "file://Sources/SwiftDemo/Shapes.swift:141:17", + "graph": "SwiftDemo.symbols.json" + }, + { + "id": "s:9SwiftDemo11MeasurementO", + "kind": "enum", + "path": "Measurement", + "name": "Measurement", + "access": "public", + "declaration": "enum Measurement", + "location": "file://Sources/SwiftDemo/Shapes.swift:60:12", + "graph": "SwiftDemo.symbols.json", + "members": [ + "s:9SwiftDemo11MeasurementO6lengthyACSdcACmF", + "s:9SwiftDemo11MeasurementO4areayACSd_SdtcACmF", + "s:9SwiftDemo11MeasurementO4noneyA2CmF", + "s:9SwiftDemo11MeasurementO4UnitV", + "s:9SwiftDemo11MeasurementO6isNoneSbvp" + ] + }, + { + "id": "s:9SwiftDemo11MeasurementO4UnitV", + "kind": "struct", + "path": "Measurement.Unit", + "name": "Unit", + "access": "public", + "declaration": "struct Unit", + "location": "file://Sources/SwiftDemo/Shapes.swift:65:18", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo11MeasurementO", + "members": [ + "s:9SwiftDemo11MeasurementO4UnitV6symbolSSvp", + "s:9SwiftDemo11MeasurementO4UnitV6symbolAESS_tcfc" + ] + }, + { + "id": "s:9SwiftDemo11MeasurementO4UnitV6symbolAESS_tcfc", + "kind": "initializer", + "path": "Measurement.Unit.init(symbol:)", + "name": "init(symbol:)", + "access": "public", + "declaration": "init(symbol: String)", + "parameters": [ + { + "label": "symbol", + "internalName": "symbol", + "type": { + "spelling": "String", + "references": [ + "s:SS" + ] + } + } + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:67:15", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo11MeasurementO4UnitV" + }, + { + "id": "s:9SwiftDemo11MeasurementO4UnitV6symbolSSvp", + "kind": "instanceProperty", + "path": "Measurement.Unit.symbol", + "name": "symbol", + "access": "public", + "declaration": "var symbol: String", + "valueType": { + "spelling": "String", + "references": [ + "s:SS" + ] + }, + "settable": true, + "location": "file://Sources/SwiftDemo/Shapes.swift:66:19", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo11MeasurementO4UnitV" + }, + { + "id": "s:9SwiftDemo11MeasurementO4areayACSd_SdtcACmF", + "kind": "enumCase", + "path": "Measurement.area(width:height:)", + "name": "area(width:height:)", + "access": "public", + "declaration": "case area(width: Double, height: Double)", + "parameters": [ + { + "label": "width", + "internalName": "width", + "type": { + "spelling": "Double", + "references": [ + "s:Sd" + ] + } + }, + { + "label": "height", + "internalName": "height", + "type": { + "spelling": "Double", + "references": [ + "s:Sd" + ] + } + } + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:62:9", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo11MeasurementO" + }, + { + "id": "s:9SwiftDemo11MeasurementO4noneyA2CmF", + "kind": "enumCase", + "path": "Measurement.none", + "name": "none", + "access": "public", + "declaration": "case none", + "location": "file://Sources/SwiftDemo/Shapes.swift:63:9", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo11MeasurementO" + }, + { + "id": "s:9SwiftDemo11MeasurementO6isNoneSbvp", + "kind": "instanceProperty", + "path": "Measurement.isNone", + "name": "isNone", + "access": "public", + "declaration": "var isNone: Bool { get }", + "valueType": { + "spelling": "Bool", + "references": [ + "s:Sb" + ] + }, + "settable": false, + "location": "file://Sources/SwiftDemo/Shapes.swift:70:15", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo11MeasurementO" + }, + { + "id": "s:9SwiftDemo11MeasurementO6lengthyACSdcACmF", + "kind": "enumCase", + "path": "Measurement.length(_:)", + "name": "length(_:)", + "access": "public", + "declaration": "case length(Double)", + "parameters": [ + { + "type": { + "spelling": "Double", + "references": [ + "s:Sd" + ] + } + } + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:61:9", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo11MeasurementO" + }, + { + "id": "s:9SwiftDemo11checkedSideyS2dKF", + "kind": "function", + "path": "checkedSide(_:)", + "name": "checkedSide(_:)", + "access": "public", + "declaration": "func checkedSide(_ side: Double) throws -> Double", + "parameters": [ + { + "internalName": "side", + "type": { + "spelling": "Double", + "references": [ + "s:Sd" + ] + } + } + ], + "returns": { + "spelling": "Double", + "references": [ + "s:Sd" + ] + }, + "throws": true, + "location": "file://Sources/SwiftDemo/Values.swift:3:12", + "graph": "SwiftDemo.symbols.json" + }, + { + "id": "s:9SwiftDemo13PrecipitationO", + "kind": "enum", + "path": "Precipitation", + "name": "Precipitation", + "access": "public", + "declaration": "enum Precipitation", + "location": "file://Sources/SwiftDemo/Shapes.swift:50:12", + "graph": "SwiftDemo.symbols.json", + "members": [ + "s:9SwiftDemo13PrecipitationO4rainyA2CmF", + "s:9SwiftDemo13PrecipitationO4snowyA2CmF", + "s:9SwiftDemo13PrecipitationO4noneyA2CmF", + "s:9SwiftDemo13PrecipitationO8rawValueACSgSS_tcfc", + "s:SQsRi_zRi0_zrlE2neoiySbx_xtFZ::SYNTHESIZED::s:9SwiftDemo13PrecipitationO", + "s:SYsSHRzSH8RawValueSYRpzrlE04hashB0Sivp::SYNTHESIZED::s:9SwiftDemo13PrecipitationO", + "s:SYsSHRzSH8RawValueSYRpzrlE4hash4intoys6HasherVz_tF::SYNTHESIZED::s:9SwiftDemo13PrecipitationO" + ], + "conformances": [ + "s:SH", + "s:SQ", + "s:SY" + ] + }, + { + "id": "s:9SwiftDemo13PrecipitationO4noneyA2CmF", + "kind": "enumCase", + "path": "Precipitation.none", + "name": "none", + "access": "public", + "declaration": "case none", + "location": "file://Sources/SwiftDemo/Shapes.swift:51:21", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo13PrecipitationO" + }, + { + "id": "s:9SwiftDemo13PrecipitationO4rainyA2CmF", + "kind": "enumCase", + "path": "Precipitation.rain", + "name": "rain", + "access": "public", + "declaration": "case rain", + "location": "file://Sources/SwiftDemo/Shapes.swift:51:9", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo13PrecipitationO" + }, + { + "id": "s:9SwiftDemo13PrecipitationO4snowyA2CmF", + "kind": "enumCase", + "path": "Precipitation.snow", + "name": "snow", + "access": "public", + "declaration": "case snow", + "location": "file://Sources/SwiftDemo/Shapes.swift:51:15", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo13PrecipitationO" + }, + { + "id": "s:9SwiftDemo13PrecipitationO8rawValueACSgSS_tcfc", + "kind": "initializer", + "path": "Precipitation.init(rawValue:)", + "name": "init(rawValue:)", + "access": "public", + "declaration": "init?(rawValue: String)", + "parameters": [ + { + "label": "rawValue", + "internalName": "rawValue", + "type": { + "spelling": "String", + "references": [ + "s:SS" + ] + } + } + ], + "failable": true, + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo13PrecipitationO", + "sourceOrigin": "s:SY8rawValuexSg03RawB0Qz_tcfc" + }, + { + "id": "s:9SwiftDemo13defaultFlavorAA0D0Ovp", + "kind": "variable", + "path": "defaultFlavor", + "name": "defaultFlavor", + "access": "public", + "declaration": "let defaultFlavor: Flavor", + "valueType": { + "spelling": "Flavor", + "references": [ + "s:9SwiftDemo6FlavorO" + ] + }, + "settable": false, + "let": true, + "location": "file://Sources/SwiftDemo/Shapes.swift:139:11", + "graph": "SwiftDemo.symbols.json" + }, + { + "id": "s:9SwiftDemo13globalCounterSivp", + "kind": "variable", + "path": "globalCounter", + "name": "globalCounter", + "access": "public", + "declaration": "var globalCounter: Int", + "valueType": { + "spelling": "Int", + "references": [ + "s:Si" + ] + }, + "settable": true, + "location": "file://Sources/SwiftDemo/Shapes.swift:140:11", + "graph": "SwiftDemo.symbols.json" + }, + { + "id": "s:9SwiftDemo16makeDefaultPointAA0E0VyF", + "kind": "function", + "path": "makeDefaultPoint()", + "name": "makeDefaultPoint()", + "access": "public", + "declaration": "func makeDefaultPoint() -> Point", + "returns": { + "spelling": "Point", + "references": [ + "s:9SwiftDemo5PointV" + ] + }, + "location": "file://Sources/SwiftDemo/Shapes.swift:138:12", + "graph": "SwiftDemo.symbols.json" + }, + { + "id": "s:9SwiftDemo4RingV", + "kind": "struct", + "path": "Ring", + "name": "Ring", + "access": "public", + "declaration": "struct Ring", + "location": "file://Sources/SwiftDemo/Shapes.swift:76:14", + "graph": "SwiftDemo.symbols.json", + "members": [ + "s:9SwiftDemo4RingV5innerAA5PointVvp", + "s:9SwiftDemo4RingV5outerAA5PointVvp", + "s:9SwiftDemo4RingV5inner5outerAcA5PointV_AGtcfc", + "s:9SwiftDemo4RingV6expand2byySd_tF", + "s:9SwiftDemo4RingV1poiyA2C_ACtFZ" + ] + }, + { + "id": "s:9SwiftDemo4RingV1poiyA2C_ACtFZ", + "kind": "operator", + "path": "Ring.+(_:_:)", + "name": "+(_:_:)", + "access": "public", + "declaration": "static func + (lhs: Ring, rhs: Ring) -> Ring", + "modifiers": [ + "static" + ], + "static": true, + "parameters": [ + { + "internalName": "lhs", + "type": { + "spelling": "Ring", + "references": [ + "s:9SwiftDemo4RingV" + ] + } + }, + { + "internalName": "rhs", + "type": { + "spelling": "Ring", + "references": [ + "s:9SwiftDemo4RingV" + ] + } + } + ], + "returns": { + "spelling": "Ring", + "references": [ + "s:9SwiftDemo4RingV" + ] + }, + "location": "file://Sources/SwiftDemo/Shapes.swift:90:23", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo4RingV" + }, + { + "id": "s:9SwiftDemo4RingV5inner5outerAcA5PointV_AGtcfc", + "kind": "initializer", + "path": "Ring.init(inner:outer:)", + "name": "init(inner:outer:)", + "access": "public", + "declaration": "init(inner: Point, outer: Point)", + "parameters": [ + { + "label": "inner", + "internalName": "inner", + "type": { + "spelling": "Point", + "references": [ + "s:9SwiftDemo5PointV" + ] + } + }, + { + "label": "outer", + "internalName": "outer", + "type": { + "spelling": "Point", + "references": [ + "s:9SwiftDemo5PointV" + ] + } + } + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:80:11", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo4RingV" + }, + { + "id": "s:9SwiftDemo4RingV5innerAA5PointVvp", + "kind": "instanceProperty", + "path": "Ring.inner", + "name": "inner", + "access": "public", + "declaration": "var inner: Point", + "valueType": { + "spelling": "Point", + "references": [ + "s:9SwiftDemo5PointV" + ] + }, + "settable": true, + "location": "file://Sources/SwiftDemo/Shapes.swift:77:15", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo4RingV" + }, + { + "id": "s:9SwiftDemo4RingV5outerAA5PointVvp", + "kind": "instanceProperty", + "path": "Ring.outer", + "name": "outer", + "access": "public", + "declaration": "var outer: Point", + "valueType": { + "spelling": "Point", + "references": [ + "s:9SwiftDemo5PointV" + ] + }, + "settable": true, + "location": "file://Sources/SwiftDemo/Shapes.swift:78:15", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo4RingV" + }, + { + "id": "s:9SwiftDemo4RingV6expand2byySd_tF", + "kind": "instanceMethod", + "path": "Ring.expand(by:)", + "name": "expand(by:)", + "access": "public", + "declaration": "mutating func expand(by delta: Double)", + "modifiers": [ + "mutating" + ], + "parameters": [ + { + "label": "by", + "internalName": "delta", + "type": { + "spelling": "Double", + "references": [ + "s:Sd" + ] + } + } + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:85:25", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo4RingV" + }, + { + "id": "s:9SwiftDemo5PointV", + "kind": "struct", + "path": "Point", + "name": "Point", + "access": "public", + "declaration": "struct Point", + "location": "file://Sources/SwiftDemo/Demo.swift:9:14", + "graph": "SwiftDemo.symbols.json", + "members": [ + "s:9SwiftDemo5PointV1xSdvp", + "s:9SwiftDemo5PointV1ySdvp", + "s:9SwiftDemo5PointV1x1yACSd_Sdtcfc", + "s:9SwiftDemo5PointV11descriptionSSvp", + "s:9SwiftDemo5PointV6lengthSdvp" + ], + "conformances": [ + "s:s23CustomStringConvertibleP", + "s:s8CopyableP", + "s:s9EscapableP" + ] + }, + { + "id": "s:9SwiftDemo5PointV11descriptionSSvp", + "kind": "instanceProperty", + "path": "Point.description", + "name": "description", + "access": "public", + "declaration": "var description: String { get }", + "valueType": { + "spelling": "String", + "references": [ + "s:SS" + ] + }, + "settable": false, + "extension": { + "extendedModule": "SwiftDemo", + "typeKind": "swift.struct" + }, + "location": "file://Sources/SwiftDemo/Extensions.swift:9:15", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo5PointV", + "sourceOrigin": "s:s23CustomStringConvertibleP11descriptionSSvp" + }, + { + "id": "s:9SwiftDemo5PointV1x1yACSd_Sdtcfc", + "kind": "initializer", + "path": "Point.init(x:y:)", + "name": "init(x:y:)", + "access": "public", + "declaration": "init(x: Double, y: Double)", + "parameters": [ + { + "label": "x", + "internalName": "x", + "type": { + "spelling": "Double", + "references": [ + "s:Sd" + ] + } + }, + { + "label": "y", + "internalName": "y", + "type": { + "spelling": "Double", + "references": [ + "s:Sd" + ] + } + } + ], + "location": "file://Sources/SwiftDemo/Demo.swift:12:11", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo5PointV" + }, + { + "id": "s:9SwiftDemo5PointV1xSdvp", + "kind": "instanceProperty", + "path": "Point.x", + "name": "x", + "access": "public", + "declaration": "var x: Double", + "valueType": { + "spelling": "Double", + "references": [ + "s:Sd" + ] + }, + "settable": true, + "location": "file://Sources/SwiftDemo/Demo.swift:10:15", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo5PointV" + }, + { + "id": "s:9SwiftDemo5PointV1ySdvp", + "kind": "instanceProperty", + "path": "Point.y", + "name": "y", + "access": "public", + "declaration": "var y: Double", + "valueType": { + "spelling": "Double", + "references": [ + "s:Sd" + ] + }, + "settable": true, + "location": "file://Sources/SwiftDemo/Demo.swift:11:15", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo5PointV" + }, + { + "id": "s:9SwiftDemo5PointV6lengthSdvp", + "kind": "instanceProperty", + "path": "Point.length", + "name": "length", + "access": "public", + "declaration": "var length: Double { get }", + "valueType": { + "spelling": "Double", + "references": [ + "s:Sd" + ] + }, + "settable": false, + "extension": { + "extendedModule": "SwiftDemo", + "typeKind": "swift.struct" + }, + "location": "file://Sources/SwiftDemo/Extensions.swift:10:15", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo5PointV" + }, + { + "id": "s:9SwiftDemo5ShapeP", + "kind": "protocol", + "path": "Shape", + "name": "Shape", + "access": "public", + "declaration": "protocol Shape : Greeter", + "location": "file://Sources/SwiftDemo/Shapes.swift:2:16", + "graph": "SwiftDemo.symbols.json", + "members": [ + "s:9SwiftDemo5ShapeP4areaSdvp", + "s:9SwiftDemo5ShapeP5sidesSivpZ" + ], + "conformances": [ + "s:9SwiftDemo7GreeterP" + ] + }, + { + "id": "s:9SwiftDemo5ShapeP4areaSdvp", + "kind": "instanceProperty", + "path": "Shape.area", + "name": "area", + "access": "public", + "declaration": "var area: Double { get }", + "protocolRequirement": true, + "valueType": { + "spelling": "Double", + "references": [ + "s:Sd" + ] + }, + "settable": false, + "location": "file://Sources/SwiftDemo/Shapes.swift:3:8", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo5ShapeP" + }, + { + "id": "s:9SwiftDemo5ShapeP5sidesSivpZ", + "kind": "typeProperty", + "path": "Shape.sides", + "name": "sides", + "access": "public", + "declaration": "static var sides: Int { get }", + "modifiers": [ + "static" + ], + "static": true, + "protocolRequirement": true, + "valueType": { + "spelling": "Int", + "references": [ + "s:Si" + ] + }, + "settable": false, + "location": "file://Sources/SwiftDemo/Shapes.swift:4:15", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo5ShapeP" + }, + { + "id": "s:9SwiftDemo5shoutySSSgACF", + "kind": "function", + "path": "shout(_:)", + "name": "shout(_:)", + "access": "public", + "declaration": "func shout(_ name: String?) -> String?", + "parameters": [ + { + "internalName": "name", + "type": { + "spelling": "String?", + "references": [ + "s:SS" + ] + } + } + ], + "returns": { + "spelling": "String?", + "references": [ + "s:SS" + ] + }, + "location": "file://Sources/SwiftDemo/Values.swift:11:12", + "graph": "SwiftDemo.symbols.json" + }, + { + "id": "s:9SwiftDemo6CanvasC", + "kind": "class", + "path": "Canvas", + "name": "Canvas", + "access": "public", + "declaration": "@MainActor final class Canvas", + "attributes": [ + "@MainActor" + ], + "modifiers": [ + "final" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:106:19", + "graph": "SwiftDemo.symbols.json", + "members": [ + "s:9SwiftDemo6CanvasCACycfc", + "s:9SwiftDemo6CanvasC4drawyyAA5Shape_pF" + ], + "conformances": [ + "s:s8SendableP" + ] + }, + { + "id": "s:9SwiftDemo6CanvasC4drawyyAA5Shape_pF", + "kind": "instanceMethod", + "path": "Canvas.draw(_:)", + "name": "draw(_:)", + "access": "public", + "declaration": "@MainActor func draw(_ shape: any Shape)", + "attributes": [ + "@MainActor" + ], + "parameters": [ + { + "internalName": "shape", + "type": { + "spelling": "any Shape", + "references": [ + "s:9SwiftDemo5ShapeP" + ] + } + } + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:108:16", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6CanvasC" + }, + { + "id": "s:9SwiftDemo6CanvasCACycfc", + "kind": "initializer", + "path": "Canvas.init()", + "name": "init()", + "access": "public", + "declaration": "@MainActor init()", + "attributes": [ + "@MainActor" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:107:11", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6CanvasC" + }, + { + "id": "s:9SwiftDemo6FlavorO", + "kind": "enum", + "path": "Flavor", + "name": "Flavor", + "access": "public", + "declaration": "enum Flavor", + "location": "file://Sources/SwiftDemo/Demo.swift:15:12", + "graph": "SwiftDemo.symbols.json", + "members": [ + "s:9SwiftDemo6FlavorO7vanillayA2CmF", + "s:9SwiftDemo6FlavorO9chocolateyA2CmF", + "s:9SwiftDemo6FlavorO11descriptionSSvp", + "s:9SwiftDemo6FlavorO8rawValueACSgSi_tcfc", + "s:SQsRi_zRi0_zrlE2neoiySbx_xtFZ::SYNTHESIZED::s:9SwiftDemo6FlavorO", + "s:SYsSHRzSH8RawValueSYRpzrlE04hashB0Sivp::SYNTHESIZED::s:9SwiftDemo6FlavorO", + "s:SYsSHRzSH8RawValueSYRpzrlE4hash4intoys6HasherVz_tF::SYNTHESIZED::s:9SwiftDemo6FlavorO" + ], + "conformances": [ + "s:SH", + "s:SQ", + "s:SY", + "s:s23CustomStringConvertibleP", + "s:s8CopyableP", + "s:s9EscapableP" + ] + }, + { + "id": "s:9SwiftDemo6FlavorO11descriptionSSvp", + "kind": "instanceProperty", + "path": "Flavor.description", + "name": "description", + "access": "public", + "declaration": "var description: String { get }", + "valueType": { + "spelling": "String", + "references": [ + "s:SS" + ] + }, + "settable": false, + "extension": { + "extendedModule": "SwiftDemo", + "typeKind": "swift.enum" + }, + "location": "file://Sources/SwiftDemo/Extensions.swift:14:15", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6FlavorO", + "sourceOrigin": "s:s23CustomStringConvertibleP11descriptionSSvp" + }, + { + "id": "s:9SwiftDemo6FlavorO7vanillayA2CmF", + "kind": "enumCase", + "path": "Flavor.vanilla", + "name": "vanilla", + "access": "public", + "declaration": "case vanilla", + "location": "file://Sources/SwiftDemo/Demo.swift:15:31", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6FlavorO" + }, + { + "id": "s:9SwiftDemo6FlavorO8rawValueACSgSi_tcfc", + "kind": "initializer", + "path": "Flavor.init(rawValue:)", + "name": "init(rawValue:)", + "access": "public", + "declaration": "init?(rawValue: Int)", + "parameters": [ + { + "label": "rawValue", + "internalName": "rawValue", + "type": { + "spelling": "Int", + "references": [ + "s:Si" + ] + } + } + ], + "failable": true, + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6FlavorO", + "sourceOrigin": "s:SY8rawValuexSg03RawB0Qz_tcfc" + }, + { + "id": "s:9SwiftDemo6FlavorO9chocolateyA2CmF", + "kind": "enumCase", + "path": "Flavor.chocolate", + "name": "chocolate", + "access": "public", + "declaration": "case chocolate", + "location": "file://Sources/SwiftDemo/Demo.swift:15:44", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6FlavorO" + }, + { + "id": "s:9SwiftDemo6LoaderC", + "kind": "class", + "path": "Loader", + "name": "Loader", + "access": "public", + "declaration": "final class Loader", + "modifiers": [ + "final" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:111:19", + "graph": "SwiftDemo.symbols.json", + "members": [ + "s:9SwiftDemo6LoaderCACycfc", + "s:9SwiftDemo6LoaderC4load4path10Foundation4DataVSS_tKF", + "s:9SwiftDemo6LoaderC5fetch3urlSS10Foundation3URLV_tYaKF", + "s:9SwiftDemo6LoaderC4wait7secondsySd_tYaF", + "s:9SwiftDemo6LoaderC9transformyxxAA5ShapeRzlF", + "s:9SwiftDemo6LoaderC5first2ofxSgSayxG_tlF", + "s:9SwiftDemo6LoaderC14withCompletionyyys6ResultOySSAA10ShapeErrorOGcF", + "s:9SwiftDemo6LoaderC4eachyyySiXEF", + "s:9SwiftDemo6LoaderC6lookup5table3keySiSgSDySSSiG_SStF", + "s:9SwiftDemo6LoaderC6updateyyAA5PointVzF", + "s:9SwiftDemo6LoaderC10modernOnlyyyF", + "s:9SwiftDemo6LoaderC11legacyFetchyyF", + "s:9SwiftDemo6LoaderC8oldFetchyyF" + ] + }, + { + "id": "s:9SwiftDemo6LoaderC10modernOnlyyyF", + "kind": "instanceMethod", + "path": "Loader.modernOnly()", + "name": "modernOnly()", + "access": "public", + "declaration": "func modernOnly()", + "availability": [ + { + "domain": "iOS", + "introduced": "16.0.0" + } + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:129:16", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6LoaderC" + }, + { + "id": "s:9SwiftDemo6LoaderC11legacyFetchyyF", + "kind": "instanceMethod", + "path": "Loader.legacyFetch()", + "name": "legacyFetch()", + "access": "public", + "declaration": "func legacyFetch()", + "availability": [ + { + "domain": "*", + "message": "Use fetch(url:) instead", + "unconditionallyDeprecated": true + } + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:132:16", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6LoaderC" + }, + { + "id": "s:9SwiftDemo6LoaderC14withCompletionyyys6ResultOySSAA10ShapeErrorOGcF", + "kind": "instanceMethod", + "path": "Loader.withCompletion(_:)", + "name": "withCompletion(_:)", + "access": "public", + "declaration": "func withCompletion(_ completion: @escaping (Result) -> Void)", + "parameters": [ + { + "internalName": "completion", + "type": { + "spelling": "(Result) -> Void", + "references": [ + "s:s6ResultO", + "s:SS", + "s:9SwiftDemo10ShapeErrorO", + "s:s4Voida" + ] + }, + "attributes": [ + "@escaping" + ] + } + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:121:16", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6LoaderC" + }, + { + "id": "s:9SwiftDemo6LoaderC4eachyyySiXEF", + "kind": "instanceMethod", + "path": "Loader.each(_:)", + "name": "each(_:)", + "access": "public", + "declaration": "func each(_ body: (Int) -> Void)", + "parameters": [ + { + "internalName": "body", + "type": { + "spelling": "(Int) -> Void", + "references": [ + "s:Si", + "s:s4Voida" + ] + } + } + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:122:16", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6LoaderC" + }, + { + "id": "s:9SwiftDemo6LoaderC4load4path10Foundation4DataVSS_tKF", + "kind": "instanceMethod", + "path": "Loader.load(path:)", + "name": "load(path:)", + "access": "public", + "declaration": "func load(path: String) throws -> Data", + "parameters": [ + { + "label": "path", + "internalName": "path", + "type": { + "spelling": "String", + "references": [ + "s:SS" + ] + } + } + ], + "returns": { + "spelling": "Data", + "references": [ + "s:10Foundation4DataV" + ] + }, + "throws": true, + "location": "file://Sources/SwiftDemo/Shapes.swift:114:16", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6LoaderC" + }, + { + "id": "s:9SwiftDemo6LoaderC4wait7secondsySd_tYaF", + "kind": "instanceMethod", + "path": "Loader.wait(seconds:)", + "name": "wait(seconds:)", + "access": "public", + "declaration": "func wait(seconds: Double) async", + "parameters": [ + { + "label": "seconds", + "internalName": "seconds", + "type": { + "spelling": "Double", + "references": [ + "s:Sd" + ] + } + } + ], + "async": true, + "location": "file://Sources/SwiftDemo/Shapes.swift:116:16", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6LoaderC" + }, + { + "id": "s:9SwiftDemo6LoaderC5fetch3urlSS10Foundation3URLV_tYaKF", + "kind": "instanceMethod", + "path": "Loader.fetch(url:)", + "name": "fetch(url:)", + "access": "public", + "declaration": "func fetch(url: URL) async throws -> String", + "parameters": [ + { + "label": "url", + "internalName": "url", + "type": { + "spelling": "URL", + "references": [ + "s:10Foundation3URLV" + ] + } + } + ], + "returns": { + "spelling": "String", + "references": [ + "s:SS" + ] + }, + "async": true, + "throws": true, + "location": "file://Sources/SwiftDemo/Shapes.swift:115:16", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6LoaderC" + }, + { + "id": "s:9SwiftDemo6LoaderC5first2ofxSgSayxG_tlF", + "kind": "instanceMethod", + "path": "Loader.first(of:)", + "name": "first(of:)", + "access": "public", + "declaration": "func first(of items: [Element]) -> Element?", + "parameters": [ + { + "label": "of", + "internalName": "items", + "type": { + "spelling": "[Element]", + "references": [ + "s:9SwiftDemo6LoaderC5first2ofxSgSayxG_tlF7ElementL_xmfp" + ] + } + } + ], + "returns": { + "spelling": "Element?" + }, + "genericParameters": [ + { + "name": "Element", + "depth": 0, + "index": 0 + } + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:119:16", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6LoaderC" + }, + { + "id": "s:9SwiftDemo6LoaderC6lookup5table3keySiSgSDySSSiG_SStF", + "kind": "instanceMethod", + "path": "Loader.lookup(table:key:)", + "name": "lookup(table:key:)", + "access": "public", + "declaration": "func lookup(table: [String : Int], key: String) -> Int?", + "parameters": [ + { + "label": "table", + "internalName": "table", + "type": { + "spelling": "[String : Int]", + "references": [ + "s:SS", + "s:Si" + ] + } + }, + { + "label": "key", + "internalName": "key", + "type": { + "spelling": "String", + "references": [ + "s:SS" + ] + } + } + ], + "returns": { + "spelling": "Int?", + "references": [ + "s:Si" + ] + }, + "location": "file://Sources/SwiftDemo/Shapes.swift:124:16", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6LoaderC" + }, + { + "id": "s:9SwiftDemo6LoaderC6updateyyAA5PointVzF", + "kind": "instanceMethod", + "path": "Loader.update(_:)", + "name": "update(_:)", + "access": "public", + "declaration": "func update(_ point: inout Point)", + "parameters": [ + { + "internalName": "point", + "type": { + "spelling": "Point", + "references": [ + "s:9SwiftDemo5PointV" + ] + }, + "modifier": "inout" + } + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:126:16", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6LoaderC" + }, + { + "id": "s:9SwiftDemo6LoaderC8oldFetchyyF", + "kind": "instanceMethod", + "path": "Loader.oldFetch()", + "name": "oldFetch()", + "access": "public", + "declaration": "func oldFetch()", + "availability": [ + { + "domain": "iOS", + "introduced": "15.0.0", + "deprecated": "17.0.0", + "renamed": "fetch(url:)" + } + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:135:16", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6LoaderC" + }, + { + "id": "s:9SwiftDemo6LoaderC9transformyxxAA5ShapeRzlF", + "kind": "instanceMethod", + "path": "Loader.transform(_:)", + "name": "transform(_:)", + "access": "public", + "declaration": "func transform(_ shape: T) -> T where T : Shape", + "parameters": [ + { + "internalName": "shape", + "type": { + "spelling": "T", + "references": [ + "s:9SwiftDemo6LoaderC9transformyxxAA5ShapeRzlF1TL_xmfp" + ] + } + } + ], + "returns": { + "spelling": "T" + }, + "genericParameters": [ + { + "name": "T", + "depth": 0, + "index": 0 + } + ], + "genericConstraints": [ + { + "kind": "conformance", + "lhs": "T", + "rhs": "Shape", + "rhsPrecise": "s:9SwiftDemo5ShapeP" + } + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:118:16", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6LoaderC" + }, + { + "id": "s:9SwiftDemo6LoaderCACycfc", + "kind": "initializer", + "path": "Loader.init()", + "name": "init()", + "access": "public", + "declaration": "init()", + "location": "file://Sources/SwiftDemo/Shapes.swift:112:11", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6LoaderC" + }, + { + "id": "s:9SwiftDemo6SquareC", + "kind": "class", + "path": "Square", + "name": "Square", + "access": "public", + "declaration": "final class Square", + "modifiers": [ + "final" + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:34:19", + "graph": "SwiftDemo.symbols.json", + "members": [ + "s:9SwiftDemo6SquareC4sideSdvp", + "s:9SwiftDemo6SquareC4sideACSd_tcfc", + "s:9SwiftDemo6SquareC4areaSdvp", + "s:9SwiftDemo6SquareC5sidesSivpZ", + "s:9SwiftDemo6SquareC5greet4nameS2S_tF", + "s:9SwiftDemo6SquareC5scale2byySd_tF" + ], + "conformances": [ + "s:9SwiftDemo5ShapeP", + "s:9SwiftDemo7GreeterP" + ], + "superclass": "s:9SwiftDemo7PolygonC" + }, + { + "id": "s:9SwiftDemo6SquareC4areaSdvp", + "kind": "instanceProperty", + "path": "Square.area", + "name": "area", + "access": "public", + "declaration": "var area: Double { get }", + "valueType": { + "spelling": "Double", + "references": [ + "s:Sd" + ] + }, + "settable": false, + "location": "file://Sources/SwiftDemo/Shapes.swift:42:15", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6SquareC", + "sourceOrigin": "s:9SwiftDemo5ShapeP4areaSdvp" + }, + { + "id": "s:9SwiftDemo6SquareC4sideACSd_tcfc", + "kind": "initializer", + "path": "Square.init(side:)", + "name": "init(side:)", + "access": "public", + "declaration": "init(side: Double)", + "parameters": [ + { + "label": "side", + "internalName": "side", + "type": { + "spelling": "Double", + "references": [ + "s:Sd" + ] + } + } + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:37:11", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6SquareC" + }, + { + "id": "s:9SwiftDemo6SquareC4sideSdvp", + "kind": "instanceProperty", + "path": "Square.side", + "name": "side", + "access": "public", + "declaration": "var side: Double", + "valueType": { + "spelling": "Double", + "references": [ + "s:Sd" + ] + }, + "settable": true, + "location": "file://Sources/SwiftDemo/Shapes.swift:35:15", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6SquareC" + }, + { + "id": "s:9SwiftDemo6SquareC5greet4nameS2S_tF", + "kind": "instanceMethod", + "path": "Square.greet(name:)", + "name": "greet(name:)", + "access": "public", + "declaration": "func greet(name: String) -> String", + "parameters": [ + { + "label": "name", + "internalName": "name", + "type": { + "spelling": "String", + "references": [ + "s:SS" + ] + } + } + ], + "returns": { + "spelling": "String", + "references": [ + "s:SS" + ] + }, + "location": "file://Sources/SwiftDemo/Shapes.swift:44:16", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6SquareC", + "sourceOrigin": "s:9SwiftDemo7GreeterP5greet4nameS2S_tF" + }, + { + "id": "s:9SwiftDemo6SquareC5scale2byySd_tF", + "kind": "instanceMethod", + "path": "Square.scale(by:)", + "name": "scale(by:)", + "access": "public", + "declaration": "override func scale(by factor: Double)", + "modifiers": [ + "override" + ], + "parameters": [ + { + "label": "by", + "internalName": "factor", + "type": { + "spelling": "Double", + "references": [ + "s:Sd" + ] + } + } + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:46:25", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6SquareC", + "overrides": "s:9SwiftDemo7PolygonC5scale2byySd_tF" + }, + { + "id": "s:9SwiftDemo6SquareC5sidesSivpZ", + "kind": "typeProperty", + "path": "Square.sides", + "name": "sides", + "access": "public", + "declaration": "static var sides: Int { get }", + "modifiers": [ + "static" + ], + "static": true, + "valueType": { + "spelling": "Int", + "references": [ + "s:Si" + ] + }, + "settable": false, + "location": "file://Sources/SwiftDemo/Shapes.swift:43:22", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6SquareC", + "sourceOrigin": "s:9SwiftDemo5ShapeP5sidesSivpZ" + }, + { + "id": "s:9SwiftDemo7CounterC", + "kind": "actor", + "path": "Counter", + "name": "Counter", + "access": "public", + "declaration": "actor Counter", + "location": "file://Sources/SwiftDemo/Shapes.swift:95:13", + "graph": "SwiftDemo.symbols.json", + "members": [ + "s:9SwiftDemo7CounterC5valueSivp", + "s:9SwiftDemo7CounterCACycfc", + "s:9SwiftDemo7CounterC9incrementSiyF", + "s:9SwiftDemo7CounterC5labelSSyF", + "s:ScA12_ConcurrencyE14assertIsolated_4file4lineySSyXK_s12StaticStringVSutF::SYNTHESIZED::s:9SwiftDemo7CounterC", + "s:ScA12_ConcurrencyE14assumeIsolated_4file4lineqd__qd__xYiKXE_s12StaticStringVSutKs8SendableRd__lF::SYNTHESIZED::s:9SwiftDemo7CounterC", + "s:ScA12_ConcurrencyE18withSerialExecutoryqd__qd__Scf_pYaqd_0_YKYCXEYaqd_0_YKs5ErrorRd_0_Ri_d__r0_lF::SYNTHESIZED::s:9SwiftDemo7CounterC", + "s:ScA12_ConcurrencyE18withSerialExecutoryqd__qd__Scf_pqd_0_YKXEqd_0_YKs5ErrorRd_0_Ri_d__r0_lF::SYNTHESIZED::s:9SwiftDemo7CounterC", + "s:ScA12_ConcurrencyE20preconditionIsolated_4file4lineySSyXK_s12StaticStringVSutF::SYNTHESIZED::s:9SwiftDemo7CounterC" + ], + "conformances": [ + "s:ScA", + "s:s16SendableMetatypeP", + "s:s8SendableP" + ] + }, + { + "id": "s:9SwiftDemo7CounterC5labelSSyF", + "kind": "instanceMethod", + "path": "Counter.label()", + "name": "label()", + "access": "public", + "declaration": "nonisolated func label() -> String", + "attributes": [ + "nonisolated" + ], + "returns": { + "spelling": "String", + "references": [ + "s:SS" + ] + }, + "location": "file://Sources/SwiftDemo/Shapes.swift:102:28", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7CounterC" + }, + { + "id": "s:9SwiftDemo7CounterC5valueSivp", + "kind": "instanceProperty", + "path": "Counter.value", + "name": "value", + "access": "public", + "declaration": "var value: Int { get }", + "valueType": { + "spelling": "Int", + "references": [ + "s:Si" + ] + }, + "settable": false, + "location": "file://Sources/SwiftDemo/Shapes.swift:96:28", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7CounterC" + }, + { + "id": "s:9SwiftDemo7CounterC9incrementSiyF", + "kind": "instanceMethod", + "path": "Counter.increment()", + "name": "increment()", + "access": "public", + "declaration": "func increment() -> Int", + "returns": { + "spelling": "Int", + "references": [ + "s:Si" + ] + }, + "location": "file://Sources/SwiftDemo/Shapes.swift:98:16", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7CounterC" + }, + { + "id": "s:9SwiftDemo7CounterCACycfc", + "kind": "initializer", + "path": "Counter.init()", + "name": "init()", + "access": "public", + "declaration": "init()", + "location": "file://Sources/SwiftDemo/Shapes.swift:97:11", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7CounterC" + }, + { + "id": "s:9SwiftDemo7GreeterP", + "kind": "protocol", + "path": "Greeter", + "name": "Greeter", + "access": "public", + "declaration": "protocol Greeter", + "location": "file://Sources/SwiftDemo/Demo.swift:0:16", + "graph": "SwiftDemo.symbols.json", + "members": [ + "s:9SwiftDemo7GreeterP5greet4nameS2S_tF" + ] + }, + { + "id": "s:9SwiftDemo7GreeterP5greet4nameS2S_tF", + "kind": "instanceMethod", + "path": "Greeter.greet(name:)", + "name": "greet(name:)", + "access": "public", + "declaration": "func greet(name: String) -> String", + "protocolRequirement": true, + "parameters": [ + { + "label": "name", + "internalName": "name", + "type": { + "spelling": "String", + "references": [ + "s:SS" + ] + } + } + ], + "returns": { + "spelling": "String", + "references": [ + "s:SS" + ] + }, + "location": "file://Sources/SwiftDemo/Demo.swift:1:9", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7GreeterP" + }, + { + "id": "s:9SwiftDemo7PolygonC", + "kind": "class", + "path": "Polygon", + "name": "Polygon", + "access": "open", + "declaration": "class Polygon", + "location": "file://Sources/SwiftDemo/Shapes.swift:7:11", + "graph": "SwiftDemo.symbols.json", + "members": [ + "s:9SwiftDemo7PolygonC4nameSSvp", + "s:9SwiftDemo7PolygonC11vertexCountSivp", + "s:9SwiftDemo7PolygonC6sharedACvpZ", + "s:9SwiftDemo7PolygonC4name11vertexCountACSS_Sitcfc", + "s:9SwiftDemo7PolygonC4nameACSgSS_tcfc", + "s:9SwiftDemo7PolygonC5scale2byySd_tF", + "s:9SwiftDemo7PolygonC5scale2byySi_tF", + "s:9SwiftDemo7PolygonC5scale1x1yySd_SdtF", + "s:9SwiftDemo7PolygonC4makeACyFZ", + "s:9SwiftDemo7PolygonC8describeySSACSgFZ", + "s:9SwiftDemo7PolygonCyAA5PointVSicip" + ] + }, + { + "id": "s:9SwiftDemo7PolygonC11vertexCountSivp", + "kind": "instanceProperty", + "path": "Polygon.vertexCount", + "name": "vertexCount", + "access": "public", + "declaration": "var vertexCount: Int { get }", + "valueType": { + "spelling": "Int", + "references": [ + "s:Si" + ] + }, + "settable": false, + "location": "file://Sources/SwiftDemo/Shapes.swift:9:28", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7PolygonC" + }, + { + "id": "s:9SwiftDemo7PolygonC4makeACyFZ", + "kind": "typeMethod", + "path": "Polygon.make()", + "name": "make()", + "access": "public", + "declaration": "class func make() -> Polygon", + "modifiers": [ + "class" + ], + "static": true, + "returns": { + "spelling": "Polygon", + "references": [ + "s:9SwiftDemo7PolygonC" + ] + }, + "location": "file://Sources/SwiftDemo/Shapes.swift:26:22", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7PolygonC" + }, + { + "id": "s:9SwiftDemo7PolygonC4name11vertexCountACSS_Sitcfc", + "kind": "initializer", + "path": "Polygon.init(name:vertexCount:)", + "name": "init(name:vertexCount:)", + "access": "public", + "declaration": "init(name: String, vertexCount: Int)", + "parameters": [ + { + "label": "name", + "internalName": "name", + "type": { + "spelling": "String", + "references": [ + "s:SS" + ] + } + }, + { + "label": "vertexCount", + "internalName": "vertexCount", + "type": { + "spelling": "Int", + "references": [ + "s:Si" + ] + } + } + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:12:11", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7PolygonC" + }, + { + "id": "s:9SwiftDemo7PolygonC4nameACSgSS_tcfc", + "kind": "initializer", + "path": "Polygon.init(name:)", + "name": "init(name:)", + "access": "public", + "declaration": "convenience init?(name: String)", + "modifiers": [ + "convenience" + ], + "parameters": [ + { + "label": "name", + "internalName": "name", + "type": { + "spelling": "String", + "references": [ + "s:SS" + ] + } + } + ], + "failable": true, + "location": "file://Sources/SwiftDemo/Shapes.swift:17:23", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7PolygonC" + }, + { + "id": "s:9SwiftDemo7PolygonC4nameSSvp", + "kind": "instanceProperty", + "path": "Polygon.name", + "name": "name", + "access": "public", + "declaration": "let name: String", + "valueType": { + "spelling": "String", + "references": [ + "s:SS" + ] + }, + "settable": false, + "let": true, + "location": "file://Sources/SwiftDemo/Shapes.swift:8:15", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7PolygonC" + }, + { + "id": "s:9SwiftDemo7PolygonC5scale1x1yySd_SdtF", + "kind": "instanceMethod", + "path": "Polygon.scale(x:y:)", + "name": "scale(x:y:)", + "access": "public", + "declaration": "func scale(x: Double, y: Double)", + "parameters": [ + { + "label": "x", + "internalName": "x", + "type": { + "spelling": "Double", + "references": [ + "s:Sd" + ] + } + }, + { + "label": "y", + "internalName": "y", + "type": { + "spelling": "Double", + "references": [ + "s:Sd" + ] + } + } + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:24:16", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7PolygonC" + }, + { + "id": "s:9SwiftDemo7PolygonC5scale2byySd_tF", + "kind": "instanceMethod", + "path": "Polygon.scale(by:)", + "name": "scale(by:)", + "access": "open", + "declaration": "func scale(by factor: Double)", + "parameters": [ + { + "label": "by", + "internalName": "factor", + "type": { + "spelling": "Double", + "references": [ + "s:Sd" + ] + } + } + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:22:14", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7PolygonC" + }, + { + "id": "s:9SwiftDemo7PolygonC5scale2byySi_tF", + "kind": "instanceMethod", + "path": "Polygon.scale(by:)", + "name": "scale(by:)", + "access": "open", + "declaration": "func scale(by factor: Int)", + "parameters": [ + { + "label": "by", + "internalName": "factor", + "type": { + "spelling": "Int", + "references": [ + "s:Si" + ] + } + } + ], + "location": "file://Sources/SwiftDemo/Shapes.swift:23:14", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7PolygonC" + }, + { + "id": "s:9SwiftDemo7PolygonC6sharedACvpZ", + "kind": "typeProperty", + "path": "Polygon.shared", + "name": "shared", + "access": "public", + "declaration": "static let shared: Polygon", + "modifiers": [ + "static" + ], + "static": true, + "valueType": { + "spelling": "Polygon", + "references": [ + "s:9SwiftDemo7PolygonC" + ] + }, + "settable": false, + "let": true, + "location": "file://Sources/SwiftDemo/Shapes.swift:10:22", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7PolygonC" + }, + { + "id": "s:9SwiftDemo7PolygonC8describeySSACSgFZ", + "kind": "typeMethod", + "path": "Polygon.describe(_:)", + "name": "describe(_:)", + "access": "public", + "declaration": "static func describe(_ polygon: Polygon?) -> String", + "modifiers": [ + "static" + ], + "static": true, + "parameters": [ + { + "internalName": "polygon", + "type": { + "spelling": "Polygon?", + "references": [ + "s:9SwiftDemo7PolygonC" + ] + } + } + ], + "returns": { + "spelling": "String", + "references": [ + "s:SS" + ] + }, + "location": "file://Sources/SwiftDemo/Shapes.swift:27:23", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7PolygonC" + }, + { + "id": "s:9SwiftDemo7PolygonCyAA5PointVSicip", + "kind": "instanceSubscript", + "path": "Polygon.subscript(_:)", + "name": "subscript(_:)", + "access": "public", + "declaration": "subscript(index: Int) -> Point { get }", + "parameters": [ + { + "internalName": "index", + "type": { + "spelling": "Int", + "references": [ + "s:Si" + ] + } + } + ], + "returns": { + "spelling": "Point", + "references": [ + "s:9SwiftDemo5PointV" + ] + }, + "valueType": { + "spelling": "Point", + "references": [ + "s:9SwiftDemo5PointV" + ] + }, + "settable": false, + "location": "file://Sources/SwiftDemo/Shapes.swift:29:11", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7PolygonC" + }, + { + "id": "s:9SwiftDemo7TrackerC", + "kind": "class", + "path": "Tracker", + "name": "Tracker", + "access": "public", + "declaration": "final class Tracker", + "modifiers": [ + "final" + ], + "location": "file://Sources/SwiftDemo/Values.swift:13:19", + "graph": "SwiftDemo.symbols.json", + "members": [ + "s:9SwiftDemo7TrackerC9liveCountSivpZ", + "s:9SwiftDemo7TrackerC2idSivp", + "s:9SwiftDemo7TrackerC2idACSi_tcfc", + "s:9SwiftDemo7TrackerC4sameACyF" + ] + }, + { + "id": "s:9SwiftDemo7TrackerC2idACSi_tcfc", + "kind": "initializer", + "path": "Tracker.init(id:)", + "name": "init(id:)", + "access": "public", + "declaration": "init(id: Int)", + "parameters": [ + { + "label": "id", + "internalName": "id", + "type": { + "spelling": "Int", + "references": [ + "s:Si" + ] + } + } + ], + "location": "file://Sources/SwiftDemo/Values.swift:17:11", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7TrackerC" + }, + { + "id": "s:9SwiftDemo7TrackerC2idSivp", + "kind": "instanceProperty", + "path": "Tracker.id", + "name": "id", + "access": "public", + "declaration": "let id: Int", + "valueType": { + "spelling": "Int", + "references": [ + "s:Si" + ] + }, + "settable": false, + "let": true, + "location": "file://Sources/SwiftDemo/Values.swift:15:15", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7TrackerC" + }, + { + "id": "s:9SwiftDemo7TrackerC4sameACyF", + "kind": "instanceMethod", + "path": "Tracker.same()", + "name": "same()", + "access": "public", + "declaration": "func same() -> Tracker", + "returns": { + "spelling": "Tracker", + "references": [ + "s:9SwiftDemo7TrackerC" + ] + }, + "location": "file://Sources/SwiftDemo/Values.swift:24:16", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7TrackerC" + }, + { + "id": "s:9SwiftDemo7TrackerC9liveCountSivpZ", + "kind": "typeProperty", + "path": "Tracker.liveCount", + "name": "liveCount", + "access": "public", + "declaration": "static var liveCount: Int { get }", + "modifiers": [ + "static" + ], + "static": true, + "valueType": { + "spelling": "Int", + "references": [ + "s:Si" + ] + }, + "settable": false, + "location": "file://Sources/SwiftDemo/Values.swift:14:35", + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7TrackerC" + }, + { + "id": "s:9SwiftDemo8echoInt8ys0D0VADF", + "kind": "function", + "path": "echoInt8(_:)", + "name": "echoInt8(_:)", + "access": "public", + "declaration": "func echoInt8(_ value: Int8) -> Int8", + "parameters": [ + { + "internalName": "value", + "type": { + "spelling": "Int8", + "references": [ + "s:s4Int8V" + ] + } + } + ], + "returns": { + "spelling": "Int8", + "references": [ + "s:s4Int8V" + ] + }, + "location": "file://Sources/SwiftDemo/Values.swift:8:12", + "graph": "SwiftDemo.symbols.json" + }, + { + "id": "s:SQsRi_zRi0_zrlE2neoiySbx_xtFZ::SYNTHESIZED::s:9SwiftDemo13PrecipitationO", + "kind": "operator", + "path": "Precipitation.!=(_:_:)", + "name": "!=(_:_:)", + "access": "public", + "declaration": "static func != (lhs: borrowing Self, rhs: borrowing Self) -> Bool", + "modifiers": [ + "static" + ], + "static": true, + "synthesized": true, + "parameters": [ + { + "internalName": "lhs", + "type": { + "spelling": "Self" + }, + "modifier": "borrowing" + }, + { + "internalName": "rhs", + "type": { + "spelling": "Self" + }, + "modifier": "borrowing" + } + ], + "returns": { + "spelling": "Bool", + "references": [ + "s:Sb" + ] + }, + "extension": { + "extendedModule": "Swift", + "typeKind": "swift.protocol" + }, + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo13PrecipitationO", + "sourceOrigin": "s:SQsRi_zRi0_zrlE2neoiySbx_xtFZ" + }, + { + "id": "s:SQsRi_zRi0_zrlE2neoiySbx_xtFZ::SYNTHESIZED::s:9SwiftDemo6FlavorO", + "kind": "operator", + "path": "Flavor.!=(_:_:)", + "name": "!=(_:_:)", + "access": "public", + "declaration": "static func != (lhs: borrowing Self, rhs: borrowing Self) -> Bool", + "modifiers": [ + "static" + ], + "static": true, + "synthesized": true, + "parameters": [ + { + "internalName": "lhs", + "type": { + "spelling": "Self" + }, + "modifier": "borrowing" + }, + { + "internalName": "rhs", + "type": { + "spelling": "Self" + }, + "modifier": "borrowing" + } + ], + "returns": { + "spelling": "Bool", + "references": [ + "s:Sb" + ] + }, + "extension": { + "extendedModule": "Swift", + "typeKind": "swift.protocol" + }, + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6FlavorO", + "sourceOrigin": "s:SQsRi_zRi0_zrlE2neoiySbx_xtFZ" + }, + { + "id": "s:SS9SwiftDemoE7shoutedSSvp", + "kind": "instanceProperty", + "path": "String.shouted", + "name": "shouted", + "access": "public", + "declaration": "var shouted: String { get }", + "valueType": { + "spelling": "String", + "references": [ + "s:SS" + ] + }, + "settable": false, + "extension": { + "extendedModule": "Swift", + "typeKind": "swift.struct" + }, + "location": "file://Sources/SwiftDemo/Extensions.swift:18:15", + "graph": "SwiftDemo@Swift.symbols.json", + "parent": "s:SS" + }, + { + "id": "s:SYsSHRzSH8RawValueSYRpzrlE04hashB0Sivp::SYNTHESIZED::s:9SwiftDemo13PrecipitationO", + "kind": "instanceProperty", + "path": "Precipitation.hashValue", + "name": "hashValue", + "access": "public", + "declaration": "var hashValue: Int { get }", + "synthesized": true, + "valueType": { + "spelling": "Int", + "references": [ + "s:Si" + ] + }, + "settable": false, + "extension": { + "extendedModule": "Swift", + "typeKind": "swift.protocol", + "constraints": [ + { + "kind": "conformance", + "lhs": "Self", + "rhs": "Hashable", + "rhsPrecise": "s:SH" + }, + { + "kind": "conformance", + "lhs": "Self.RawValue", + "rhs": "Hashable", + "rhsPrecise": "s:SH" + } + ] + }, + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo13PrecipitationO", + "sourceOrigin": "s:SYsSHRzSH8RawValueSYRpzrlE04hashB0Sivp" + }, + { + "id": "s:SYsSHRzSH8RawValueSYRpzrlE04hashB0Sivp::SYNTHESIZED::s:9SwiftDemo6FlavorO", + "kind": "instanceProperty", + "path": "Flavor.hashValue", + "name": "hashValue", + "access": "public", + "declaration": "var hashValue: Int { get }", + "synthesized": true, + "valueType": { + "spelling": "Int", + "references": [ + "s:Si" + ] + }, + "settable": false, + "extension": { + "extendedModule": "Swift", + "typeKind": "swift.protocol", + "constraints": [ + { + "kind": "conformance", + "lhs": "Self", + "rhs": "Hashable", + "rhsPrecise": "s:SH" + }, + { + "kind": "conformance", + "lhs": "Self.RawValue", + "rhs": "Hashable", + "rhsPrecise": "s:SH" + } + ] + }, + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6FlavorO", + "sourceOrigin": "s:SYsSHRzSH8RawValueSYRpzrlE04hashB0Sivp" + }, + { + "id": "s:SYsSHRzSH8RawValueSYRpzrlE4hash4intoys6HasherVz_tF::SYNTHESIZED::s:9SwiftDemo13PrecipitationO", + "kind": "instanceMethod", + "path": "Precipitation.hash(into:)", + "name": "hash(into:)", + "access": "public", + "declaration": "func hash(into hasher: inout Hasher)", + "synthesized": true, + "parameters": [ + { + "label": "into", + "internalName": "hasher", + "type": { + "spelling": "Hasher", + "references": [ + "s:s6HasherV" + ] + }, + "modifier": "inout" + } + ], + "genericConstraints": [ + { + "kind": "conformance", + "lhs": "Self", + "rhs": "Hashable", + "rhsPrecise": "s:SH" + }, + { + "kind": "conformance", + "lhs": "Self.RawValue", + "rhs": "Hashable", + "rhsPrecise": "s:SH" + } + ], + "extension": { + "extendedModule": "Swift", + "typeKind": "swift.protocol", + "constraints": [ + { + "kind": "conformance", + "lhs": "Self", + "rhs": "Hashable", + "rhsPrecise": "s:SH" + }, + { + "kind": "conformance", + "lhs": "Self.RawValue", + "rhs": "Hashable", + "rhsPrecise": "s:SH" + } + ] + }, + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo13PrecipitationO", + "sourceOrigin": "s:SYsSHRzSH8RawValueSYRpzrlE4hash4intoys6HasherVz_tF" + }, + { + "id": "s:SYsSHRzSH8RawValueSYRpzrlE4hash4intoys6HasherVz_tF::SYNTHESIZED::s:9SwiftDemo6FlavorO", + "kind": "instanceMethod", + "path": "Flavor.hash(into:)", + "name": "hash(into:)", + "access": "public", + "declaration": "func hash(into hasher: inout Hasher)", + "synthesized": true, + "parameters": [ + { + "label": "into", + "internalName": "hasher", + "type": { + "spelling": "Hasher", + "references": [ + "s:s6HasherV" + ] + }, + "modifier": "inout" + } + ], + "genericConstraints": [ + { + "kind": "conformance", + "lhs": "Self", + "rhs": "Hashable", + "rhsPrecise": "s:SH" + }, + { + "kind": "conformance", + "lhs": "Self.RawValue", + "rhs": "Hashable", + "rhsPrecise": "s:SH" + } + ], + "extension": { + "extendedModule": "Swift", + "typeKind": "swift.protocol", + "constraints": [ + { + "kind": "conformance", + "lhs": "Self", + "rhs": "Hashable", + "rhsPrecise": "s:SH" + }, + { + "kind": "conformance", + "lhs": "Self.RawValue", + "rhs": "Hashable", + "rhsPrecise": "s:SH" + } + ] + }, + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo6FlavorO", + "sourceOrigin": "s:SYsSHRzSH8RawValueSYRpzrlE4hash4intoys6HasherVz_tF" + }, + { + "id": "s:Sa9SwiftDemoAA5PointVRszlE8centroidACyF", + "kind": "instanceMethod", + "path": "Array.centroid()", + "name": "centroid()", + "access": "public", + "declaration": "func centroid() -> Point", + "returns": { + "spelling": "Point", + "references": [ + "s:9SwiftDemo5PointV" + ] + }, + "genericParameters": [ + { + "name": "Element", + "depth": 0, + "index": 0 + } + ], + "genericConstraints": [ + { + "kind": "sameType", + "lhs": "Element", + "rhs": "Point", + "rhsPrecise": "s:9SwiftDemo5PointV" + } + ], + "extension": { + "extendedModule": "Swift", + "typeKind": "swift.struct", + "constraints": [ + { + "kind": "sameType", + "lhs": "Element", + "rhs": "Point", + "rhsPrecise": "s:9SwiftDemo5PointV" + } + ] + }, + "location": "file://Sources/SwiftDemo/Extensions.swift:22:16", + "graph": "SwiftDemo@Swift.symbols.json", + "parent": "s:Sa" + }, + { + "id": "s:ScA12_ConcurrencyE14assertIsolated_4file4lineySSyXK_s12StaticStringVSutF::SYNTHESIZED::s:9SwiftDemo7CounterC", + "kind": "instanceMethod", + "path": "Counter.assertIsolated(_:file:line:)", + "name": "assertIsolated(_:file:line:)", + "access": "public", + "declaration": "@backDeployed(before: macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0)\nnonisolated func assertIsolated(_ message: @autoclosure () -> String = String(), file: StaticString = #fileID, line: UInt = #line)", + "attributes": [ + "@backDeployed(before: macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0)", + "nonisolated" + ], + "synthesized": true, + "parameters": [ + { + "internalName": "message", + "type": { + "spelling": "() -> String", + "references": [ + "s:SS" + ] + }, + "attributes": [ + "@autoclosure" + ], + "default": "String()" + }, + { + "label": "file", + "internalName": "file", + "type": { + "spelling": "StaticString", + "references": [ + "s:s12StaticStringV" + ] + }, + "default": "#fileID" + }, + { + "label": "line", + "internalName": "line", + "type": { + "spelling": "UInt", + "references": [ + "s:Su" + ] + }, + "default": "#line" + } + ], + "extension": { + "extendedModule": "_Concurrency", + "typeKind": "swift.protocol" + }, + "availability": [ + { + "domain": "iOS", + "introduced": "13.0.0" + }, + { + "domain": "macOS", + "introduced": "10.15.0" + }, + { + "domain": "tvOS", + "introduced": "13.0.0" + }, + { + "domain": "watchOS", + "introduced": "6.0.0" + } + ], + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7CounterC", + "sourceOrigin": "s:ScA12_ConcurrencyE14assertIsolated_4file4lineySSyXK_s12StaticStringVSutF" + }, + { + "id": "s:ScA12_ConcurrencyE14assumeIsolated_4file4lineqd__qd__xYiKXE_s12StaticStringVSutKs8SendableRd__lF::SYNTHESIZED::s:9SwiftDemo7CounterC", + "kind": "instanceMethod", + "path": "Counter.assumeIsolated(_:file:line:)", + "name": "assumeIsolated(_:file:line:)", + "access": "public", + "declaration": "nonisolated func assumeIsolated(_ operation: (isolated Self) throws -> T, file: StaticString = #fileID, line: UInt = #line) rethrows -> T where T : Sendable", + "attributes": [ + "nonisolated" + ], + "synthesized": true, + "parameters": [ + { + "internalName": "operation", + "type": { + "spelling": "(isolated Self) throws -> T" + } + }, + { + "label": "file", + "internalName": "file", + "type": { + "spelling": "StaticString", + "references": [ + "s:s12StaticStringV" + ] + }, + "default": "#fileID" + }, + { + "label": "line", + "internalName": "line", + "type": { + "spelling": "UInt", + "references": [ + "s:Su" + ] + }, + "default": "#line" + } + ], + "returns": { + "spelling": "T" + }, + "throws": true, + "rethrows": true, + "genericParameters": [ + { + "name": "T", + "depth": 1, + "index": 0 + } + ], + "genericConstraints": [ + { + "kind": "conformance", + "lhs": "T", + "rhs": "Sendable", + "rhsPrecise": "s:s8SendableP" + } + ], + "extension": { + "extendedModule": "_Concurrency", + "typeKind": "swift.protocol" + }, + "availability": [ + { + "domain": "iOS", + "introduced": "13.0.0" + }, + { + "domain": "macOS", + "introduced": "10.15.0" + }, + { + "domain": "tvOS", + "introduced": "13.0.0" + }, + { + "domain": "watchOS", + "introduced": "6.0.0" + } + ], + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7CounterC", + "sourceOrigin": "s:ScA12_ConcurrencyE14assumeIsolated_4file4lineqd__qd__xYiKXE_s12StaticStringVSutKs8SendableRd__lF" + }, + { + "id": "s:ScA12_ConcurrencyE18withSerialExecutoryqd__qd__Scf_pYaqd_0_YKYCXEYaqd_0_YKs5ErrorRd_0_Ri_d__r0_lF::SYNTHESIZED::s:9SwiftDemo7CounterC", + "kind": "instanceMethod", + "path": "Counter.withSerialExecutor(_:)", + "name": "withSerialExecutor(_:)", + "access": "public", + "declaration": "nonisolated func withSerialExecutor(_ operation: nonisolated(nonsending) (any SerialExecutor) async throws(E) -> T) async throws(E) -> T where E : Error, T : ~Copyable", + "attributes": [ + "nonisolated" + ], + "synthesized": true, + "parameters": [ + { + "internalName": "operation", + "type": { + "spelling": "nonisolated(nonsending) (any SerialExecutor) async throws(E) -> T", + "references": [ + "s:Scf" + ] + } + } + ], + "returns": { + "spelling": "T" + }, + "async": true, + "throws": true, + "thrownType": { + "spelling": "E" + }, + "genericParameters": [ + { + "name": "T", + "depth": 1, + "index": 0 + }, + { + "name": "E", + "depth": 1, + "index": 1 + } + ], + "genericConstraints": [ + { + "kind": "conformance", + "lhs": "E", + "rhs": "Error", + "rhsPrecise": "s:s5ErrorP" + } + ], + "extension": { + "extendedModule": "_Concurrency", + "typeKind": "swift.protocol" + }, + "availability": [ + { + "domain": "iOS", + "introduced": "13.0.0" + }, + { + "domain": "macOS", + "introduced": "10.15.0" + }, + { + "domain": "tvOS", + "introduced": "13.0.0" + }, + { + "domain": "watchOS", + "introduced": "6.0.0" + } + ], + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7CounterC", + "sourceOrigin": "s:ScA12_ConcurrencyE18withSerialExecutoryqd__qd__Scf_pYaqd_0_YKYCXEYaqd_0_YKs5ErrorRd_0_Ri_d__r0_lF" + }, + { + "id": "s:ScA12_ConcurrencyE18withSerialExecutoryqd__qd__Scf_pqd_0_YKXEqd_0_YKs5ErrorRd_0_Ri_d__r0_lF::SYNTHESIZED::s:9SwiftDemo7CounterC", + "kind": "instanceMethod", + "path": "Counter.withSerialExecutor(_:)", + "name": "withSerialExecutor(_:)", + "access": "public", + "declaration": "nonisolated func withSerialExecutor(_ operation: (any SerialExecutor) throws(E) -> T) throws(E) -> T where E : Error, T : ~Copyable", + "attributes": [ + "nonisolated" + ], + "synthesized": true, + "parameters": [ + { + "internalName": "operation", + "type": { + "spelling": "(any SerialExecutor) throws(E) -> T", + "references": [ + "s:Scf" + ] + } + } + ], + "returns": { + "spelling": "T" + }, + "throws": true, + "thrownType": { + "spelling": "E" + }, + "genericParameters": [ + { + "name": "T", + "depth": 1, + "index": 0 + }, + { + "name": "E", + "depth": 1, + "index": 1 + } + ], + "genericConstraints": [ + { + "kind": "conformance", + "lhs": "E", + "rhs": "Error", + "rhsPrecise": "s:s5ErrorP" + } + ], + "extension": { + "extendedModule": "_Concurrency", + "typeKind": "swift.protocol" + }, + "availability": [ + { + "domain": "iOS", + "introduced": "13.0.0" + }, + { + "domain": "macOS", + "introduced": "10.15.0" + }, + { + "domain": "tvOS", + "introduced": "13.0.0" + }, + { + "domain": "watchOS", + "introduced": "6.0.0" + } + ], + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7CounterC", + "sourceOrigin": "s:ScA12_ConcurrencyE18withSerialExecutoryqd__qd__Scf_pqd_0_YKXEqd_0_YKs5ErrorRd_0_Ri_d__r0_lF" + }, + { + "id": "s:ScA12_ConcurrencyE20preconditionIsolated_4file4lineySSyXK_s12StaticStringVSutF::SYNTHESIZED::s:9SwiftDemo7CounterC", + "kind": "instanceMethod", + "path": "Counter.preconditionIsolated(_:file:line:)", + "name": "preconditionIsolated(_:file:line:)", + "access": "public", + "declaration": "@backDeployed(before: macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0)\nnonisolated func preconditionIsolated(_ message: @autoclosure () -> String = String(), file: StaticString = #fileID, line: UInt = #line)", + "attributes": [ + "@backDeployed(before: macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0)", + "nonisolated" + ], + "synthesized": true, + "parameters": [ + { + "internalName": "message", + "type": { + "spelling": "() -> String", + "references": [ + "s:SS" + ] + }, + "attributes": [ + "@autoclosure" + ], + "default": "String()" + }, + { + "label": "file", + "internalName": "file", + "type": { + "spelling": "StaticString", + "references": [ + "s:s12StaticStringV" + ] + }, + "default": "#fileID" + }, + { + "label": "line", + "internalName": "line", + "type": { + "spelling": "UInt", + "references": [ + "s:Su" + ] + }, + "default": "#line" + } + ], + "extension": { + "extendedModule": "_Concurrency", + "typeKind": "swift.protocol" + }, + "availability": [ + { + "domain": "iOS", + "introduced": "13.0.0" + }, + { + "domain": "macOS", + "introduced": "10.15.0" + }, + { + "domain": "tvOS", + "introduced": "13.0.0" + }, + { + "domain": "watchOS", + "introduced": "6.0.0" + } + ], + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo7CounterC", + "sourceOrigin": "s:ScA12_ConcurrencyE20preconditionIsolated_4file4lineySSyXK_s12StaticStringVSutF" + }, + { + "id": "s:s5ErrorP10FoundationE20localizedDescriptionSSvp::SYNTHESIZED::s:9SwiftDemo10ShapeErrorO", + "kind": "instanceProperty", + "path": "ShapeError.localizedDescription", + "name": "localizedDescription", + "access": "public", + "declaration": "var localizedDescription: String { get }", + "synthesized": true, + "valueType": { + "spelling": "String", + "references": [ + "s:SS" + ] + }, + "settable": false, + "extension": { + "extendedModule": "Swift", + "typeKind": "swift.protocol" + }, + "availability": [ + { + "domain": "iOS", + "introduced": "8.0.0" + }, + { + "domain": "macOS", + "introduced": "10.10.0" + }, + { + "domain": "tvOS", + "introduced": "9.0.0" + }, + { + "domain": "watchOS", + "introduced": "2.0.0" + } + ], + "graph": "SwiftDemo.symbols.json", + "parent": "s:9SwiftDemo10ShapeErrorO", + "sourceOrigin": "s:s5ErrorP10FoundationE20localizedDescriptionSSvp" + } + ] +} diff --git a/metadata-generator/tests/swift/snapshots/SwiftDemo.probe.swift b/metadata-generator/tests/swift/snapshots/SwiftDemo.probe.swift new file mode 100644 index 000000000..0888be6dc --- /dev/null +++ b/metadata-generator/tests/swift/snapshots/SwiftDemo.probe.swift @@ -0,0 +1,330 @@ +// Generated by objc-metadata-generator. Compiler-validation probes for +// the Swift-generated surface of module SwiftDemo. +import Foundation +import SwiftDemo + +// s:9SwiftDemo0B0C +func __nsProbe0(_ value: SwiftDemo.Demo) -> SwiftDemo.Demo { value } + +// s:9SwiftDemo0B0C5greet4name5timesS2S_SitF +func __nsProbe1(_ receiver: SwiftDemo.Demo, _ a0: String, _ a1: Int) { + let _: String = receiver.`greet`(name: a0, times: a1) +} + +// s:9SwiftDemo0B0C5greet4nameS2S_tF +func __nsProbe2(_ receiver: SwiftDemo.Demo, _ a0: String) { + let _: String = receiver.`greet`(name: a0) +} + +// s:9SwiftDemo0B0C7versionSSvpZ +func __nsProbe3() { + let _: String = SwiftDemo.Demo.`version` +} + +// s:9SwiftDemo0B0CACycfc +func __nsProbe4() { + let _: SwiftDemo.Demo = SwiftDemo.Demo() +} + +// s:9SwiftDemo10echoUInt64ys0D0VADF +func __nsProbe5(_ a0: UInt64) { + let _: UInt64 = SwiftDemo.`echoUInt64`(a0) +} + +// s:9SwiftDemo10largestIntSiyF +func __nsProbe6() { + let _: Int = SwiftDemo.`largestInt`() +} + +// s:9SwiftDemo11checkedSideyS2dKF +func __nsProbe7(_ a0: Double) throws { + let _: Double = try SwiftDemo.`checkedSide`(a0) +} + +// s:9SwiftDemo13PrecipitationO +func __nsProbe8(_ value: SwiftDemo.Precipitation) -> SwiftDemo.Precipitation { value } + +// s:9SwiftDemo13PrecipitationO4noneyA2CmF +func __nsProbe9() { + let _: SwiftDemo.Precipitation = SwiftDemo.Precipitation.`none` +} + +// s:9SwiftDemo13PrecipitationO4rainyA2CmF +func __nsProbe10() { + let _: SwiftDemo.Precipitation = SwiftDemo.Precipitation.`rain` +} + +// s:9SwiftDemo13PrecipitationO4snowyA2CmF +func __nsProbe11() { + let _: SwiftDemo.Precipitation = SwiftDemo.Precipitation.`snow` +} + +// s:9SwiftDemo13PrecipitationO8rawValueACSgSS_tcfc +func __nsProbe12(_ a0: String) { + let _: SwiftDemo.Precipitation? = SwiftDemo.Precipitation(rawValue: a0) +} + +// s:9SwiftDemo13defaultFlavorAA0D0Ovp +func __nsProbe13() { + let _: SwiftDemo.Flavor = SwiftDemo.`defaultFlavor` +} + +// s:9SwiftDemo13globalCounterSivp +func __nsProbe14(_ newValue: Int) { + let _: Int = SwiftDemo.`globalCounter` + SwiftDemo.`globalCounter` = newValue +} + +// s:9SwiftDemo16makeDefaultPointAA0E0VyF +func __nsProbe15() { + let _: SwiftDemo.Point = SwiftDemo.`makeDefaultPoint`() +} + +// s:9SwiftDemo4RingV +func __nsProbe16(_ value: SwiftDemo.Ring) -> SwiftDemo.Ring { value } + +// s:9SwiftDemo4RingV5inner5outerAcA5PointV_AGtcfc +func __nsProbe17(_ a0: SwiftDemo.Point, _ a1: SwiftDemo.Point) { + let _: SwiftDemo.Ring = SwiftDemo.Ring(inner: a0, outer: a1) +} + +// s:9SwiftDemo4RingV5innerAA5PointVvp +func __nsProbe18(_ receiver: inout SwiftDemo.Ring, _ newValue: SwiftDemo.Point) { + let _: SwiftDemo.Point = receiver.`inner` + receiver.`inner` = newValue +} + +// s:9SwiftDemo4RingV5outerAA5PointVvp +func __nsProbe19(_ receiver: inout SwiftDemo.Ring, _ newValue: SwiftDemo.Point) { + let _: SwiftDemo.Point = receiver.`outer` + receiver.`outer` = newValue +} + +// s:9SwiftDemo4RingV6expand2byySd_tF +func __nsProbe20(_ receiver: inout SwiftDemo.Ring, _ a0: Double) { + let _: Void = receiver.`expand`(by: a0) +} + +// s:9SwiftDemo5PointV +func __nsProbe21(_ value: SwiftDemo.Point) -> SwiftDemo.Point { value } + +// s:9SwiftDemo5PointV11descriptionSSvp +func __nsProbe22(_ receiver: SwiftDemo.Point) { + let _: String = receiver.`description` +} + +// s:9SwiftDemo5PointV1x1yACSd_Sdtcfc +func __nsProbe23(_ a0: Double, _ a1: Double) { + let _: SwiftDemo.Point = SwiftDemo.Point(x: a0, y: a1) +} + +// s:9SwiftDemo5PointV1xSdvp +func __nsProbe24(_ receiver: inout SwiftDemo.Point, _ newValue: Double) { + let _: Double = receiver.`x` + receiver.`x` = newValue +} + +// s:9SwiftDemo5PointV1ySdvp +func __nsProbe25(_ receiver: inout SwiftDemo.Point, _ newValue: Double) { + let _: Double = receiver.`y` + receiver.`y` = newValue +} + +// s:9SwiftDemo5PointV6lengthSdvp +func __nsProbe26(_ receiver: SwiftDemo.Point) { + let _: Double = receiver.`length` +} + +// s:9SwiftDemo5shoutySSSgACF +func __nsProbe27(_ a0: String?) { + let _: String? = SwiftDemo.`shout`(a0) +} + +// s:9SwiftDemo6CanvasC +func __nsProbe28(_ value: SwiftDemo.Canvas) -> SwiftDemo.Canvas { value } + +// s:9SwiftDemo6FlavorO +func __nsProbe29(_ value: SwiftDemo.Flavor) -> SwiftDemo.Flavor { value } + +// s:9SwiftDemo6FlavorO11descriptionSSvp +func __nsProbe30(_ receiver: SwiftDemo.Flavor) { + let _: String = receiver.`description` +} + +// s:9SwiftDemo6FlavorO7vanillayA2CmF +func __nsProbe31() { + let _: SwiftDemo.Flavor = SwiftDemo.Flavor.`vanilla` +} + +// s:9SwiftDemo6FlavorO8rawValueACSgSi_tcfc +func __nsProbe32(_ a0: Int) { + let _: SwiftDemo.Flavor? = SwiftDemo.Flavor(rawValue: a0) +} + +// s:9SwiftDemo6FlavorO9chocolateyA2CmF +func __nsProbe33() { + let _: SwiftDemo.Flavor = SwiftDemo.Flavor.`chocolate` +} + +// s:9SwiftDemo6LoaderC +func __nsProbe34(_ value: SwiftDemo.Loader) -> SwiftDemo.Loader { value } + +// s:9SwiftDemo6LoaderC10modernOnlyyyF +@available(iOS 16.0, *) +func __nsProbe35(_ receiver: SwiftDemo.Loader) { + let _: Void = receiver.`modernOnly`() +} + +// s:9SwiftDemo6LoaderC11legacyFetchyyF +func __nsProbe36(_ receiver: SwiftDemo.Loader) { + let _: Void = receiver.`legacyFetch`() +} + +// s:9SwiftDemo6LoaderC8oldFetchyyF +func __nsProbe37(_ receiver: SwiftDemo.Loader) { + let _: Void = receiver.`oldFetch`() +} + +// s:9SwiftDemo6LoaderCACycfc +func __nsProbe38() { + let _: SwiftDemo.Loader = SwiftDemo.Loader() +} + +// s:9SwiftDemo6SquareC +func __nsProbe39(_ value: SwiftDemo.Square) -> SwiftDemo.Square { value } + +// s:9SwiftDemo6SquareC4areaSdvp +func __nsProbe40(_ receiver: SwiftDemo.Square) { + let _: Double = receiver.`area` +} + +// s:9SwiftDemo6SquareC4sideACSd_tcfc +func __nsProbe41(_ a0: Double) { + let _: SwiftDemo.Square = SwiftDemo.Square(side: a0) +} + +// s:9SwiftDemo6SquareC4sideSdvp +func __nsProbe42(_ receiver: SwiftDemo.Square, _ newValue: Double) { + let _: Double = receiver.`side` + receiver.`side` = newValue +} + +// s:9SwiftDemo6SquareC5greet4nameS2S_tF +func __nsProbe43(_ receiver: SwiftDemo.Square, _ a0: String) { + let _: String = receiver.`greet`(name: a0) +} + +// s:9SwiftDemo6SquareC5scale2byySd_tF +func __nsProbe44(_ receiver: SwiftDemo.Square, _ a0: Double) { + let _: Void = receiver.`scale`(by: a0) +} + +// s:9SwiftDemo6SquareC5sidesSivpZ +func __nsProbe45() { + let _: Int = SwiftDemo.Square.`sides` +} + +// s:9SwiftDemo7CounterC +func __nsProbe46(_ value: SwiftDemo.Counter) -> SwiftDemo.Counter { value } + +// s:9SwiftDemo7CounterC5labelSSyF +func __nsProbe47(_ receiver: SwiftDemo.Counter) { + let _: String = receiver.`label`() +} + +// s:9SwiftDemo7CounterCACycfc +func __nsProbe48() { + let _: SwiftDemo.Counter = SwiftDemo.Counter() +} + +// s:9SwiftDemo7PolygonC +func __nsProbe49(_ value: SwiftDemo.Polygon) -> SwiftDemo.Polygon { value } + +// s:9SwiftDemo7PolygonC11vertexCountSivp +func __nsProbe50(_ receiver: SwiftDemo.Polygon) { + let _: Int = receiver.`vertexCount` +} + +// s:9SwiftDemo7PolygonC4makeACyFZ +func __nsProbe51() { + let _: SwiftDemo.Polygon = SwiftDemo.Polygon.`make`() +} + +// s:9SwiftDemo7PolygonC4name11vertexCountACSS_Sitcfc +func __nsProbe52(_ a0: String, _ a1: Int) { + let _: SwiftDemo.Polygon = SwiftDemo.Polygon(name: a0, vertexCount: a1) +} + +// s:9SwiftDemo7PolygonC4nameACSgSS_tcfc +func __nsProbe53(_ a0: String) { + let _: SwiftDemo.Polygon? = SwiftDemo.Polygon(name: a0) +} + +// s:9SwiftDemo7PolygonC4nameSSvp +func __nsProbe54(_ receiver: SwiftDemo.Polygon) { + let _: String = receiver.`name` +} + +// s:9SwiftDemo7PolygonC5scale1x1yySd_SdtF +func __nsProbe55(_ receiver: SwiftDemo.Polygon, _ a0: Double, _ a1: Double) { + let _: Void = receiver.`scale`(x: a0, y: a1) +} + +// s:9SwiftDemo7PolygonC5scale2byySd_tF +func __nsProbe56(_ receiver: SwiftDemo.Polygon, _ a0: Double) { + let _: Void = receiver.`scale`(by: a0) +} + +// s:9SwiftDemo7PolygonC5scale2byySi_tF +func __nsProbe57(_ receiver: SwiftDemo.Polygon, _ a0: Int) { + let _: Void = receiver.`scale`(by: a0) +} + +// s:9SwiftDemo7PolygonC6sharedACvpZ +func __nsProbe58() { + let _: SwiftDemo.Polygon = SwiftDemo.Polygon.`shared` +} + +// s:9SwiftDemo7PolygonC8describeySSACSgFZ +func __nsProbe59(_ a0: SwiftDemo.Polygon?) { + let _: String = SwiftDemo.Polygon.`describe`(a0) +} + +// s:9SwiftDemo7TrackerC +func __nsProbe60(_ value: SwiftDemo.Tracker) -> SwiftDemo.Tracker { value } + +// s:9SwiftDemo7TrackerC2idACSi_tcfc +func __nsProbe61(_ a0: Int) { + let _: SwiftDemo.Tracker = SwiftDemo.Tracker(id: a0) +} + +// s:9SwiftDemo7TrackerC2idSivp +func __nsProbe62(_ receiver: SwiftDemo.Tracker) { + let _: Int = receiver.`id` +} + +// s:9SwiftDemo7TrackerC4sameACyF +func __nsProbe63(_ receiver: SwiftDemo.Tracker) { + let _: SwiftDemo.Tracker = receiver.`same`() +} + +// s:9SwiftDemo7TrackerC9liveCountSivpZ +func __nsProbe64() { + let _: Int = SwiftDemo.Tracker.`liveCount` +} + +// s:9SwiftDemo8echoInt8ys0D0VADF +func __nsProbe65(_ a0: Int8) { + let _: Int8 = SwiftDemo.`echoInt8`(a0) +} + +// s:SYsSHRzSH8RawValueSYRpzrlE04hashB0Sivp::SYNTHESIZED::s:9SwiftDemo13PrecipitationO +func __nsProbe66(_ receiver: SwiftDemo.Precipitation) { + let _: Int = receiver.`hashValue` +} + +// s:SYsSHRzSH8RawValueSYRpzrlE04hashB0Sivp::SYNTHESIZED::s:9SwiftDemo6FlavorO +func __nsProbe67(_ receiver: SwiftDemo.Flavor) { + let _: Int = receiver.`hashValue` +} + diff --git a/metadata-generator/tests/swift/snapshots/swift!SwiftDemo.d.ts b/metadata-generator/tests/swift/snapshots/swift!SwiftDemo.d.ts new file mode 100644 index 000000000..575d20803 --- /dev/null +++ b/metadata-generator/tests/swift/snapshots/swift!SwiftDemo.d.ts @@ -0,0 +1,125 @@ +// Generated by objc-metadata-generator from the SwiftDemo symbol graphs. Do not edit. +// The JavaScript surface ns:swift exposes for SwiftDemo: every declaration is backed by a generated thunk. + +declare module "ns:swift/SwiftDemo" { + export class Demo { + constructor(); + greet(name: string, times: number | bigint): string; + greet(name: string): string; + "greet(name:times:)"(name: string, times: number | bigint): string; + "greet(name:)"(name: string): string; + static readonly version: string; + } + + export type Precipitation = "none" | "rain" | "snow"; + export const Precipitation: { + readonly none: "none"; + readonly rain: "rain"; + readonly snow: "snow"; + init(rawValue: string): Precipitation | null; + hashValue(value: Precipitation): number; + }; + + export class Ring { + constructor(inner: Point, outer: Point); + constructor(args: { inner: Point; outer: Point }); + inner: Point; + outer: Point; + expand(delta: number): void; + } + + export class Point { + constructor(x: number, y: number); + constructor(args: { x: number; y: number }); + readonly description: string; + x: number; + y: number; + readonly length: number; + } + + export class Canvas { + private constructor(); + } + + export type Flavor = "vanilla" | "chocolate"; + export const Flavor: { + description(value: Flavor): string; + readonly vanilla: "vanilla"; + init(rawValue: number | bigint): Flavor | null; + readonly chocolate: "chocolate"; + hashValue(value: Flavor): number; + }; + + export class Loader { + constructor(); + /** + * @remarks Requires iOS 16.0; throws on earlier versions. + */ + modernOnly(): void; + /** + * @deprecated Use fetch(url:) instead + */ + legacyFetch(): void; + /** + * @deprecated Renamed to `fetch(url:)`. + */ + oldFetch(): void; + } + + export class Square extends Polygon { + constructor(side: number); + constructor(args: { side: number }); + readonly area: number; + side: number; + greet(name: string): string; + scale(x: number, y: number): void; + "scale(by: Double)"(factor: number): void; + "scale(x:y:)"(x: number, y: number): void; + "scale(by: Int)"(factor: number | bigint): void; + static readonly sides: number; + } + + export class Counter { + constructor(); + label(): string; + } + + export class Polygon { + constructor(name: string, vertexCount: number | bigint); + constructor(args: { name: string; vertexCount: number | bigint }); + constructor(name: string); + constructor(args: { name: string }); + readonly vertexCount: number; + static make(): Polygon; + readonly name: string; + scale(x: number, y: number): void; + "scale(x:y:)"(x: number, y: number): void; + "scale(by: Double)"(factor: number): void; + "scale(by: Int)"(factor: number | bigint): void; + static readonly shared: Polygon; + static describe(polygon: Polygon | null | undefined): string; + } + + export class Tracker { + constructor(id: number | bigint); + constructor(args: { id: number | bigint }); + readonly id: number; + same(): Tracker; + static readonly liveCount: number; + } + + export function echoUInt64(value: number | bigint): number; + export function largestInt(): number; + export function checkedSide(side: number): number; + export const defaultFlavor: Flavor; + export let globalCounter: number; + export function makeDefaultPoint(): Point; + export function shout(name: string | null | undefined): string | null; + export function echoInt8(value: number | bigint): number; +} + +declare module "ns:swift" { + interface SwiftModules { + SwiftDemo: typeof import("ns:swift/SwiftDemo"); + } +} diff --git a/metadata-generator/tests/swift/typescript/usage.ts b/metadata-generator/tests/swift/typescript/usage.ts new file mode 100644 index 000000000..8cb9d3302 --- /dev/null +++ b/metadata-generator/tests/swift/typescript/usage.ts @@ -0,0 +1,30 @@ +// Type-checked by the TypeScriptUsageCompiles test against types/index.d.ts and +// the generated swift!SwiftDemo.d.ts snapshot. Every @ts-expect-error line +// must fail to compile: an unused directive is itself an error. +import * as swift from "ns:swift"; +import { Demo, Point, Flavor, Polygon, Square, Tracker, shout, globalCounter } from "ns:swift/SwiftDemo"; + +const SwiftDemo = swift.module("SwiftDemo"); +const demo: Demo = new SwiftDemo.Demo(); +const greeting: string = demo.greet("NativeScript"); +const twice: string = demo.greet("a", 2n); +const point = new Point({ x: 2, y: 3 }); +const x: number = point.x; +point.y = 4; +const flavor: Flavor = Flavor.init(1) ?? Flavor.vanilla; +const text: string = Flavor.description(flavor); +const square: Polygon = new Square(3); +square["scale(by: Int)"](2); +const maybe: string | null = shout(null); +const live: number = Tracker.liveCount; +const counter: number = globalCounter; + +// @ts-expect-error description is read-only +point.description = "x"; +// @ts-expect-error ambiguous overloads are not callable by base name +square.scale(2); +// @ts-expect-error Flavor is a union of case names +const bad: Flavor = "mint"; +// @ts-expect-error Canvas has no initializer callable from JavaScript +new SwiftDemo.Canvas(); +void [greeting, twice, x, text, maybe, live, counter, bad];