diff --git a/.dir-locals.el b/.dir-locals.el index 5adff096515..01f1003c829 100644 --- a/.dir-locals.el +++ b/.dir-locals.el @@ -6,7 +6,8 @@ ((x (dir-locals-find-file default-directory)) (this-directory (if (listp x) (car x) (file-name-directory x)))) (unless (or (featurep 'swift-project-settings) - (tramp-tramp-file-p this-directory)) + (and (fboundp 'tramp-tramp-file-p) + (tramp-tramp-file-p this-directory))) (add-to-list 'load-path (concat this-directory "utils") :append) diff --git a/CODE_OWNERS.TXT b/CODE_OWNERS.TXT index d2d13f290d3..322a261d0e3 100644 --- a/CODE_OWNERS.TXT +++ b/CODE_OWNERS.TXT @@ -15,9 +15,9 @@ N: Erik Eckstein E: eeckstein@apple.com D: SILOptimizer -N: David Farler -E: dfarler@apple.com -D: Markup, lib/Syntax, Swift Linux port +N: Xi Ge +E: xi_ge@apple.com +D: Markup, Migrator, lib/Syntax N: Doug Gregor E: dgregor@apple.com diff --git a/apinotes/CMakeLists.txt b/apinotes/CMakeLists.txt index 907b835d7c1..7043d3ea0d3 100644 --- a/apinotes/CMakeLists.txt +++ b/apinotes/CMakeLists.txt @@ -30,6 +30,7 @@ set(SWIFT_API_NOTES_INPUTS MediaPlayer MessageUI Metal + ModelIO MultipeerConnectivity NetworkExtension NotificationCenter @@ -39,6 +40,7 @@ set(SWIFT_API_NOTES_INPUTS QuickLook SafariServices SceneKit + ScreenSaver ScriptingBridge SpriteKit StoreKit diff --git a/apinotes/ModelIO.apinotes b/apinotes/ModelIO.apinotes new file mode 100644 index 00000000000..652025a712c --- /dev/null +++ b/apinotes/ModelIO.apinotes @@ -0,0 +1,43 @@ +--- +Name: ModelIO +Classes: +- Name: MDLAnimatedScalar + Methods: + - Selector: 'floatAtTime:' + MethodKind: Instance + SwiftName: 'floatValue(atTime:)' + - Selector: 'doubleAtTime:' + MethodKind: Instance + SwiftName: 'doubleValue(atTime:)' +- Name: MDLAnimatedVector2 + Methods: + - Selector: 'float2AtTime:' + MethodKind: Instance + SwiftName: 'float2Value(atTime:)' + - Selector: 'double2AtTime:' + MethodKind: Instance + SwiftName: 'double2Value(atTime:)' +- Name: MDLAnimatedVector3 + Methods: + - Selector: 'float3AtTime:' + MethodKind: Instance + SwiftName: 'float3Value(atTime:)' + - Selector: 'double3AtTime:' + MethodKind: Instance + SwiftName: 'double3Value(atTime:)' +- Name: MDLAnimatedVector4 + Methods: + - Selector: 'float4AtTime:' + MethodKind: Instance + SwiftName: 'float4Value(atTime:)' + - Selector: 'double4AtTime:' + MethodKind: Instance + SwiftName: 'double4Value(atTime:)' +- Name: MDLAnimatedMatrix4x4 + Methods: + - Selector: 'float4x4AtTime:' + MethodKind: Instance + SwiftName: 'float4x4Value(atTime:)' + - Selector: 'double4x4AtTime:' + MethodKind: Instance + SwiftName: 'double4x4Value(atTime:)' diff --git a/apinotes/ScreenSaver.apinotes b/apinotes/ScreenSaver.apinotes new file mode 100644 index 00000000000..070b6fad21b --- /dev/null +++ b/apinotes/ScreenSaver.apinotes @@ -0,0 +1,13 @@ +--- +Name: ScreenSaver +SwiftVersions: +- Version: 3 + Classes: + - Name: ScreenSaverView + Properties: + - Name: hasConfigureSheet + PropertyKind: Instance + SwiftImportAsAccessors: true + - Name: configureSheet + PropertyKind: Instance + SwiftImportAsAccessors: true diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index 2d97f02a5e2..d9971cdb7c1 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -50,7 +50,6 @@ set(SWIFT_BENCH_MODULES single-source/ErrorHandling single-source/ExistentialPerformance single-source/Fibonacci - single-source/GlobalClass single-source/Hanoi single-source/Hash single-source/HashQuadratic diff --git a/benchmark/scripts/Benchmark_Driver b/benchmark/scripts/Benchmark_Driver index 55c790e8fbc..648c9364843 100755 --- a/benchmark/scripts/Benchmark_Driver +++ b/benchmark/scripts/Benchmark_Driver @@ -124,13 +124,13 @@ def get_tests(driver_path, args): if args.benchmarks or args.filters: driver.append('--run-all') tests = subprocess.check_output(driver).split()[2:] - tests.extend(map(str, range(1, len(tests) + 1))) # ordinal numbers if args.filters: regexes = [re.compile(pattern) for pattern in args.filters] return sorted(list(set([name for pattern in regexes for name in tests if pattern.match(name)]))) if not args.benchmarks: return tests + tests.extend(map(str, range(1, len(tests) + 1))) # ordinal numbers return sorted(list(set(tests).intersection(set(args.benchmarks)))) diff --git a/benchmark/single-source/BitCount.swift b/benchmark/single-source/BitCount.swift index 8d5194b107a..d0d02091d66 100644 --- a/benchmark/single-source/BitCount.swift +++ b/benchmark/single-source/BitCount.swift @@ -31,10 +31,12 @@ func countBitSet(_ num: Int) -> Int { @inline(never) public func run_BitCount(_ N: Int) { - for _ in 1...100*N { + var sum = 0 + for _ in 1...1000*N { // Check some results. - CheckResults(countBitSet(1) == 1) - CheckResults(countBitSet(2) == 1) - CheckResults(countBitSet(2457) == 6) + sum = sum &+ countBitSet(getInt(1)) + &+ countBitSet(getInt(2)) + &+ countBitSet(getInt(2457)) } + CheckResults(sum == 8 * 1000 * N) } diff --git a/benchmark/single-source/ByteSwap.swift b/benchmark/single-source/ByteSwap.swift index 87f1006dbed..d0487ca340d 100644 --- a/benchmark/single-source/ByteSwap.swift +++ b/benchmark/single-source/ByteSwap.swift @@ -17,6 +17,7 @@ import Foundation import TestsUtils // a naive O(n) implementation of byteswap. +@inline(never) func byteswap_n(_ a: UInt64) -> UInt64 { #if swift(>=4) return ((a & 0x00000000000000FF) &<< 56) | @@ -40,6 +41,7 @@ func byteswap_n(_ a: UInt64) -> UInt64 { } // a O(logn) implementation of byteswap. +@inline(never) func byteswap_logn(_ a: UInt64) -> UInt64 { var a = a a = (a & 0x00000000FFFFFFFF) << 32 | (a & 0xFFFFFFFF00000000) >> 32 @@ -50,10 +52,13 @@ func byteswap_logn(_ a: UInt64) -> UInt64 { @inline(never) public func run_ByteSwap(_ N: Int) { - for _ in 1...100*N { + var s: UInt64 = 0 + for _ in 1...10000*N { // Check some results. - CheckResults(byteswap_logn(byteswap_n(2457)) == 2457) - CheckResults(byteswap_logn(byteswap_n(9129)) == 9129) - CheckResults(byteswap_logn(byteswap_n(3333)) == 3333) + let x : UInt64 = UInt64(getInt(0)) + s = s &+ byteswap_logn(byteswap_n(x &+ 2457)) + &+ byteswap_logn(byteswap_n(x &+ 9129)) + &+ byteswap_logn(byteswap_n(x &+ 3333)) } + CheckResults(s == (2457 &+ 9129 &+ 3333) &* 10000 &* N) } diff --git a/benchmark/single-source/DictionaryGroup.swift b/benchmark/single-source/DictionaryGroup.swift index e37b8671f4f..9ea53938215 100644 --- a/benchmark/single-source/DictionaryGroup.swift +++ b/benchmark/single-source/DictionaryGroup.swift @@ -12,13 +12,16 @@ import TestsUtils +let count = 10_000 +let result = count / 10 + @inline(never) public func run_DictionaryGroup(_ N: Int) { - let count = 100 * N - let result = count / 10 + for _ in 1...N { let dict = Dictionary(grouping: 0.. : Hashable { @@ -39,9 +42,10 @@ class Box : Hashable { @inline(never) public func run_DictionaryGroupOfObjects(_ N: Int) { - let count = 20 * N - let result = count / 10 - let dict = Dictionary(grouping: (0.. Int - { - return a + 1 - } -} - -var x = 0 -var a = A() -@inline(never) -public func run_GlobalClass(_ N: Int) { - for _ in 0.. String { - var sb = "a" +func buildString(_ i: String) -> String { + var sb = i for str in ["b","c","d","pizza"] { sb += str } @@ -24,26 +24,26 @@ func buildString() -> String { @inline(never) public func run_StringBuilder(_ N: Int) { for _ in 1...5000*N { - _ = buildString() + _ = buildString(getString("a")) } } @inline(never) -func addString() -> String { - let s = "a" + "b" + "c" + "d" + "pizza" +func addString(_ i: String) -> String { + let s = i + "b" + "c" + "d" + "pizza" return s } @inline(never) public func run_StringAdder(_ N: Int) { for _ in 1...5000*N { - _ = addString() + _ = addString(getString("a")) } } @inline(never) -func buildStringUTF16() -> String { - var sb = "a" +func buildStringUTF16(_ i: String) -> String { + var sb = i for str in ["🎉","c","d","pizza"] { sb += str } @@ -53,14 +53,14 @@ func buildStringUTF16() -> String { @inline(never) public func run_StringUTF16Builder(_ N: Int) { for _ in 1...5000*N { - _ = buildStringUTF16() + _ = buildStringUTF16("a") } } @inline(never) -func buildStringLong() -> String { - var sb = "👻" +func buildStringLong(_ i: String) -> String { + var sb = i let long = "Swift is a multi-paradigm, compiled programming language created for iOS, OS X, watchOS, tvOS and Linux development by Apple Inc. Swift is designed to work with Apple's Cocoa and Cocoa Touch frameworks and the large body of existing Objective-C code written for Apple products. Swift is intended to be more resilient to erroneous code (\"safer\") than Objective-C and also more concise. It is built with the LLVM compiler framework included in Xcode 6 and later and uses the Objective-C runtime, which allows C, Objective-C, C++ and Swift code to run within a single program." sb += long return sb @@ -71,7 +71,7 @@ func buildStringLong() -> String { @inline(never) public func run_StringBuilderLong(_ N: Int) { for _ in 1...5000*N { - _ = buildStringLong() + _ = buildStringLong("👻") } } diff --git a/benchmark/single-source/StringWalk.swift b/benchmark/single-source/StringWalk.swift index 5ae755f2bbb..1998b23de81 100644 --- a/benchmark/single-source/StringWalk.swift +++ b/benchmark/single-source/StringWalk.swift @@ -16,15 +16,11 @@ // scripts/generate_harness/generate_harness.py to regenerate this file. //////////////////////////////////////////////////////////////////////////////// - -// Test String subscript performance. // -// Subscript has a slow path that initializes a global variable: -// Swift._cocoaStringSubscript.addressor. Global optimization would -// normally hoist the initializer outside the inner loop (over -// unicodeScalars), forcing the initializer to be called on each -// lap. However, no that the cocoa code is properly marked "slowPath", -// no hoisting should occur. +// Test String iteration performance over a variety of workloads, languages, +// and symbols. +// + import TestsUtils var count: Int = 0 @@ -70,6 +66,8 @@ let japanese = "今回のアップデートでSwiftに大幅な改良が施さ let chinese = "Swift 是面向 Apple 平台的编程语言,功能强大且直观易用,而本次更新对其进行了全面优化。" let korean = "이번 업데이트에서는 강력하면서도 직관적인 Apple 플랫폼용 프로그래밍 언어인 Swift를 완벽히 개선하였습니다." let russian = "в чащах юга жил-был цитрус? да, но фальшивый экземпляр" +let punctuated = "\u{201c}Hello\u{2010}world\u{2026}\u{201d}" +let punctuatedJapanese = "\u{300c}\u{300e}今日は\u{3001}世界\u{3002}\u{300f}\u{300d}" // A workload that's mostly Latin characters, with occasional emoji // interspersed. Common for tweets. @@ -106,6 +104,8 @@ public func run_StringWalk_ascii_unicodeScalars_Backwards(_ N: Int) { } + + @inline(never) public func run_StringWalk_ascii_characters(_ N: Int) { for _ in 1...charactersMultiplier*N { @@ -121,6 +121,59 @@ public func run_StringWalk_ascii_characters_Backwards(_ N: Int) { } + + +let asciiCharacters = Array(ascii) + +@inline(never) +public func run_CharIteration_ascii_unicodeScalars(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in asciiCharacters { + for u in c.unicodeScalars { + count |= Int(u.value) + } + } + } +} + +@inline(never) +public func run_CharIteration_ascii_unicodeScalars_Backwards(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in asciiCharacters { + for u in c.unicodeScalars.reversed() { + count |= Int(u.value) + } + } + } +} + +@inline(never) +public func run_CharIndexing_ascii_unicodeScalars(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in asciiCharacters { + let s = c.unicodeScalars + for i in s.indices { + count |= Int(s[i].value) + } + } + } +} + +@inline(never) +public func run_CharIndexing_ascii_unicodeScalars_Backwards(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in asciiCharacters { + let s = c.unicodeScalars + for i in s.indices.reversed() { + count |= Int(s[i].value) + } + } + } +} + + + + @inline(never) public func run_StringWalk_utf16_unicodeScalars(_ N: Int) { for _ in 1...unicodeScalarsMultiplier*N { @@ -136,6 +189,8 @@ public func run_StringWalk_utf16_unicodeScalars_Backwards(_ N: Int) { } + + @inline(never) public func run_StringWalk_utf16_characters(_ N: Int) { for _ in 1...charactersMultiplier*N { @@ -151,6 +206,59 @@ public func run_StringWalk_utf16_characters_Backwards(_ N: Int) { } + + +let utf16Characters = Array(utf16) + +@inline(never) +public func run_CharIteration_utf16_unicodeScalars(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in utf16Characters { + for u in c.unicodeScalars { + count |= Int(u.value) + } + } + } +} + +@inline(never) +public func run_CharIteration_utf16_unicodeScalars_Backwards(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in utf16Characters { + for u in c.unicodeScalars.reversed() { + count |= Int(u.value) + } + } + } +} + +@inline(never) +public func run_CharIndexing_utf16_unicodeScalars(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in utf16Characters { + let s = c.unicodeScalars + for i in s.indices { + count |= Int(s[i].value) + } + } + } +} + +@inline(never) +public func run_CharIndexing_utf16_unicodeScalars_Backwards(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in utf16Characters { + let s = c.unicodeScalars + for i in s.indices.reversed() { + count |= Int(s[i].value) + } + } + } +} + + + + @inline(never) public func run_StringWalk_tweet_unicodeScalars(_ N: Int) { for _ in 1...unicodeScalarsMultiplier*N { @@ -166,6 +274,8 @@ public func run_StringWalk_tweet_unicodeScalars_Backwards(_ N: Int) { } + + @inline(never) public func run_StringWalk_tweet_characters(_ N: Int) { for _ in 1...charactersMultiplier*N { @@ -181,6 +291,59 @@ public func run_StringWalk_tweet_characters_Backwards(_ N: Int) { } + + +let tweetCharacters = Array(tweet) + +@inline(never) +public func run_CharIteration_tweet_unicodeScalars(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in tweetCharacters { + for u in c.unicodeScalars { + count |= Int(u.value) + } + } + } +} + +@inline(never) +public func run_CharIteration_tweet_unicodeScalars_Backwards(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in tweetCharacters { + for u in c.unicodeScalars.reversed() { + count |= Int(u.value) + } + } + } +} + +@inline(never) +public func run_CharIndexing_tweet_unicodeScalars(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in tweetCharacters { + let s = c.unicodeScalars + for i in s.indices { + count |= Int(s[i].value) + } + } + } +} + +@inline(never) +public func run_CharIndexing_tweet_unicodeScalars_Backwards(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in tweetCharacters { + let s = c.unicodeScalars + for i in s.indices.reversed() { + count |= Int(s[i].value) + } + } + } +} + + + + @inline(never) public func run_StringWalk_japanese_unicodeScalars(_ N: Int) { for _ in 1...unicodeScalarsMultiplier*N { @@ -196,6 +359,8 @@ public func run_StringWalk_japanese_unicodeScalars_Backwards(_ N: Int) { } + + @inline(never) public func run_StringWalk_japanese_characters(_ N: Int) { for _ in 1...charactersMultiplier*N { @@ -211,6 +376,59 @@ public func run_StringWalk_japanese_characters_Backwards(_ N: Int) { } + + +let japaneseCharacters = Array(japanese) + +@inline(never) +public func run_CharIteration_japanese_unicodeScalars(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in japaneseCharacters { + for u in c.unicodeScalars { + count |= Int(u.value) + } + } + } +} + +@inline(never) +public func run_CharIteration_japanese_unicodeScalars_Backwards(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in japaneseCharacters { + for u in c.unicodeScalars.reversed() { + count |= Int(u.value) + } + } + } +} + +@inline(never) +public func run_CharIndexing_japanese_unicodeScalars(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in japaneseCharacters { + let s = c.unicodeScalars + for i in s.indices { + count |= Int(s[i].value) + } + } + } +} + +@inline(never) +public func run_CharIndexing_japanese_unicodeScalars_Backwards(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in japaneseCharacters { + let s = c.unicodeScalars + for i in s.indices.reversed() { + count |= Int(s[i].value) + } + } + } +} + + + + @inline(never) public func run_StringWalk_chinese_unicodeScalars(_ N: Int) { for _ in 1...unicodeScalarsMultiplier*N { @@ -226,6 +444,8 @@ public func run_StringWalk_chinese_unicodeScalars_Backwards(_ N: Int) { } + + @inline(never) public func run_StringWalk_chinese_characters(_ N: Int) { for _ in 1...charactersMultiplier*N { @@ -241,6 +461,59 @@ public func run_StringWalk_chinese_characters_Backwards(_ N: Int) { } + + +let chineseCharacters = Array(chinese) + +@inline(never) +public func run_CharIteration_chinese_unicodeScalars(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in chineseCharacters { + for u in c.unicodeScalars { + count |= Int(u.value) + } + } + } +} + +@inline(never) +public func run_CharIteration_chinese_unicodeScalars_Backwards(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in chineseCharacters { + for u in c.unicodeScalars.reversed() { + count |= Int(u.value) + } + } + } +} + +@inline(never) +public func run_CharIndexing_chinese_unicodeScalars(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in chineseCharacters { + let s = c.unicodeScalars + for i in s.indices { + count |= Int(s[i].value) + } + } + } +} + +@inline(never) +public func run_CharIndexing_chinese_unicodeScalars_Backwards(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in chineseCharacters { + let s = c.unicodeScalars + for i in s.indices.reversed() { + count |= Int(s[i].value) + } + } + } +} + + + + @inline(never) public func run_StringWalk_korean_unicodeScalars(_ N: Int) { for _ in 1...unicodeScalarsMultiplier*N { @@ -256,6 +529,8 @@ public func run_StringWalk_korean_unicodeScalars_Backwards(_ N: Int) { } + + @inline(never) public func run_StringWalk_korean_characters(_ N: Int) { for _ in 1...charactersMultiplier*N { @@ -271,6 +546,59 @@ public func run_StringWalk_korean_characters_Backwards(_ N: Int) { } + + +let koreanCharacters = Array(korean) + +@inline(never) +public func run_CharIteration_korean_unicodeScalars(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in koreanCharacters { + for u in c.unicodeScalars { + count |= Int(u.value) + } + } + } +} + +@inline(never) +public func run_CharIteration_korean_unicodeScalars_Backwards(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in koreanCharacters { + for u in c.unicodeScalars.reversed() { + count |= Int(u.value) + } + } + } +} + +@inline(never) +public func run_CharIndexing_korean_unicodeScalars(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in koreanCharacters { + let s = c.unicodeScalars + for i in s.indices { + count |= Int(s[i].value) + } + } + } +} + +@inline(never) +public func run_CharIndexing_korean_unicodeScalars_Backwards(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in koreanCharacters { + let s = c.unicodeScalars + for i in s.indices.reversed() { + count |= Int(s[i].value) + } + } + } +} + + + + @inline(never) public func run_StringWalk_russian_unicodeScalars(_ N: Int) { for _ in 1...unicodeScalarsMultiplier*N { @@ -286,6 +614,8 @@ public func run_StringWalk_russian_unicodeScalars_Backwards(_ N: Int) { } + + @inline(never) public func run_StringWalk_russian_characters(_ N: Int) { for _ in 1...charactersMultiplier*N { @@ -300,3 +630,226 @@ public func run_StringWalk_russian_characters_Backwards(_ N: Int) { } } + + + +let russianCharacters = Array(russian) + +@inline(never) +public func run_CharIteration_russian_unicodeScalars(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in russianCharacters { + for u in c.unicodeScalars { + count |= Int(u.value) + } + } + } +} + +@inline(never) +public func run_CharIteration_russian_unicodeScalars_Backwards(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in russianCharacters { + for u in c.unicodeScalars.reversed() { + count |= Int(u.value) + } + } + } +} + +@inline(never) +public func run_CharIndexing_russian_unicodeScalars(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in russianCharacters { + let s = c.unicodeScalars + for i in s.indices { + count |= Int(s[i].value) + } + } + } +} + +@inline(never) +public func run_CharIndexing_russian_unicodeScalars_Backwards(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in russianCharacters { + let s = c.unicodeScalars + for i in s.indices.reversed() { + count |= Int(s[i].value) + } + } + } +} + + + + +@inline(never) +public func run_StringWalk_punctuated_unicodeScalars(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + count_unicodeScalars(punctuated.unicodeScalars) + } +} + +@inline(never) +public func run_StringWalk_punctuated_unicodeScalars_Backwards(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + count_unicodeScalars_rev(punctuated.unicodeScalars.reversed()) + } +} + + + + +@inline(never) +public func run_StringWalk_punctuated_characters(_ N: Int) { + for _ in 1...charactersMultiplier*N { + count_characters(punctuated.characters) + } +} + +@inline(never) +public func run_StringWalk_punctuated_characters_Backwards(_ N: Int) { + for _ in 1...charactersMultiplier*N { + count_characters_rev(punctuated.characters.reversed()) + } +} + + + + +let punctuatedCharacters = Array(punctuated) + +@inline(never) +public func run_CharIteration_punctuated_unicodeScalars(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in punctuatedCharacters { + for u in c.unicodeScalars { + count |= Int(u.value) + } + } + } +} + +@inline(never) +public func run_CharIteration_punctuated_unicodeScalars_Backwards(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in punctuatedCharacters { + for u in c.unicodeScalars.reversed() { + count |= Int(u.value) + } + } + } +} + +@inline(never) +public func run_CharIndexing_punctuated_unicodeScalars(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in punctuatedCharacters { + let s = c.unicodeScalars + for i in s.indices { + count |= Int(s[i].value) + } + } + } +} + +@inline(never) +public func run_CharIndexing_punctuated_unicodeScalars_Backwards(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in punctuatedCharacters { + let s = c.unicodeScalars + for i in s.indices.reversed() { + count |= Int(s[i].value) + } + } + } +} + + + + +@inline(never) +public func run_StringWalk_punctuatedJapanese_unicodeScalars(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + count_unicodeScalars(punctuatedJapanese.unicodeScalars) + } +} + +@inline(never) +public func run_StringWalk_punctuatedJapanese_unicodeScalars_Backwards(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + count_unicodeScalars_rev(punctuatedJapanese.unicodeScalars.reversed()) + } +} + + + + +@inline(never) +public func run_StringWalk_punctuatedJapanese_characters(_ N: Int) { + for _ in 1...charactersMultiplier*N { + count_characters(punctuatedJapanese.characters) + } +} + +@inline(never) +public func run_StringWalk_punctuatedJapanese_characters_Backwards(_ N: Int) { + for _ in 1...charactersMultiplier*N { + count_characters_rev(punctuatedJapanese.characters.reversed()) + } +} + + + + +let punctuatedJapaneseCharacters = Array(punctuatedJapanese) + +@inline(never) +public func run_CharIteration_punctuatedJapanese_unicodeScalars(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in punctuatedJapaneseCharacters { + for u in c.unicodeScalars { + count |= Int(u.value) + } + } + } +} + +@inline(never) +public func run_CharIteration_punctuatedJapanese_unicodeScalars_Backwards(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in punctuatedJapaneseCharacters { + for u in c.unicodeScalars.reversed() { + count |= Int(u.value) + } + } + } +} + +@inline(never) +public func run_CharIndexing_punctuatedJapanese_unicodeScalars(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in punctuatedJapaneseCharacters { + let s = c.unicodeScalars + for i in s.indices { + count |= Int(s[i].value) + } + } + } +} + +@inline(never) +public func run_CharIndexing_punctuatedJapanese_unicodeScalars_Backwards(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in punctuatedJapaneseCharacters { + let s = c.unicodeScalars + for i in s.indices.reversed() { + count |= Int(s[i].value) + } + } + } +} + + + diff --git a/benchmark/single-source/StringWalk.swift.gyb b/benchmark/single-source/StringWalk.swift.gyb index 690d01b95ad..d2094273d43 100644 --- a/benchmark/single-source/StringWalk.swift.gyb +++ b/benchmark/single-source/StringWalk.swift.gyb @@ -17,15 +17,11 @@ // scripts/generate_harness/generate_harness.py to regenerate this file. //////////////////////////////////////////////////////////////////////////////// - -// Test String subscript performance. // -// Subscript has a slow path that initializes a global variable: -// Swift._cocoaStringSubscript.addressor. Global optimization would -// normally hoist the initializer outside the inner loop (over -// unicodeScalars), forcing the initializer to be called on each -// lap. However, no that the cocoa code is properly marked "slowPath", -// no hoisting should occur. +// Test String iteration performance over a variety of workloads, languages, +// and symbols. +// + import TestsUtils var count: Int = 0 @@ -71,6 +67,8 @@ let japanese = "今回のアップデートでSwiftに大幅な改良が施さ let chinese = "Swift 是面向 Apple 平台的编程语言,功能强大且直观易用,而本次更新对其进行了全面优化。" let korean = "이번 업데이트에서는 강력하면서도 직관적인 Apple 플랫폼용 프로그래밍 언어인 Swift를 완벽히 개선하였습니다." let russian = "в чащах юга жил-был цитрус? да, но фальшивый экземпляр" +let punctuated = "\u{201c}Hello\u{2010}world\u{2026}\u{201d}" +let punctuatedJapanese = "\u{300c}\u{300e}今日は\u{3001}世界\u{3002}\u{300f}\u{300d}" // A workload that's mostly Latin characters, with occasional emoji // interspersed. Common for tweets. @@ -91,7 +89,7 @@ let baseMultiplier = 10_000 let unicodeScalarsMultiplier = baseMultiplier let charactersMultiplier = baseMultiplier / 5 -% for Name in ["ascii", "utf16", "tweet", "japanese", "chinese", "korean", "russian"]: +% for Name in ["ascii", "utf16", "tweet", "japanese", "chinese", "korean", "russian", "punctuated", "punctuatedJapanese"]: % for Kind in ["unicodeScalars", "characters"]: @inline(never) @@ -108,5 +106,58 @@ public func run_StringWalk_${Name}_${Kind}_Backwards(_ N: Int) { } } + + % end + +let ${Name}Characters = Array(${Name}) + +@inline(never) +public func run_CharIteration_${Name}_unicodeScalars(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in ${Name}Characters { + for u in c.unicodeScalars { + count |= Int(u.value) + } + } + } +} + +@inline(never) +public func run_CharIteration_${Name}_unicodeScalars_Backwards(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in ${Name}Characters { + for u in c.unicodeScalars.reversed() { + count |= Int(u.value) + } + } + } +} + +@inline(never) +public func run_CharIndexing_${Name}_unicodeScalars(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in ${Name}Characters { + let s = c.unicodeScalars + for i in s.indices { + count |= Int(s[i].value) + } + } + } +} + +@inline(never) +public func run_CharIndexing_${Name}_unicodeScalars_Backwards(_ N: Int) { + for _ in 1...unicodeScalarsMultiplier*N { + for c in ${Name}Characters { + let s = c.unicodeScalars + for i in s.indices.reversed() { + count |= Int(s[i].value) + } + } + } +} + + + % end diff --git a/benchmark/utils/TestsUtils.swift b/benchmark/utils/TestsUtils.swift index 38159315bd5..b34230c137e 100644 --- a/benchmark/utils/TestsUtils.swift +++ b/benchmark/utils/TestsUtils.swift @@ -91,3 +91,13 @@ public func someProtocolFactory() -> SomeProtocol { return MyStruct() } // which are using it. public func blackHole(_ x: T) { } + +// Return the passed argument without letting the optimizer know that. +// It's important that this function is in another module than the tests +// which are using it. +@inline(never) +public func getInt(_ x: Int) -> Int { return x } + +// The same for String. +@inline(never) +public func getString(_ s: String) -> String { return s } diff --git a/benchmark/utils/main.swift b/benchmark/utils/main.swift index 8e42e7f0aef..6a4b6fe2587 100644 --- a/benchmark/utils/main.swift +++ b/benchmark/utils/main.swift @@ -55,7 +55,6 @@ import DropWhile import ErrorHandling import ExistentialPerformance import Fibonacci -import GlobalClass import Hanoi import Hash import HashQuadratic @@ -171,6 +170,42 @@ addTo(&precommitTests, "CStringLongNonAscii", run_CStringLongNonAscii) addTo(&precommitTests, "CStringShortAscii", run_CStringShortAscii) addTo(&precommitTests, "Calculator", run_Calculator) addTo(&precommitTests, "CaptureProp", run_CaptureProp) +addTo(&precommitTests, "CharIndexing_ascii_unicodeScalars", run_CharIndexing_ascii_unicodeScalars) +addTo(&precommitTests, "CharIndexing_ascii_unicodeScalars_Backwards", run_CharIndexing_ascii_unicodeScalars_Backwards) +addTo(&precommitTests, "CharIndexing_chinese_unicodeScalars", run_CharIndexing_chinese_unicodeScalars) +addTo(&precommitTests, "CharIndexing_chinese_unicodeScalars_Backwards", run_CharIndexing_chinese_unicodeScalars_Backwards) +addTo(&precommitTests, "CharIndexing_japanese_unicodeScalars", run_CharIndexing_japanese_unicodeScalars) +addTo(&precommitTests, "CharIndexing_japanese_unicodeScalars_Backwards", run_CharIndexing_japanese_unicodeScalars_Backwards) +addTo(&precommitTests, "CharIndexing_korean_unicodeScalars", run_CharIndexing_korean_unicodeScalars) +addTo(&precommitTests, "CharIndexing_korean_unicodeScalars_Backwards", run_CharIndexing_korean_unicodeScalars_Backwards) +addTo(&precommitTests, "CharIndexing_punctuatedJapanese_unicodeScalars", run_CharIndexing_punctuatedJapanese_unicodeScalars) +addTo(&precommitTests, "CharIndexing_punctuatedJapanese_unicodeScalars_Backwards", run_CharIndexing_punctuatedJapanese_unicodeScalars_Backwards) +addTo(&precommitTests, "CharIndexing_punctuated_unicodeScalars", run_CharIndexing_punctuated_unicodeScalars) +addTo(&precommitTests, "CharIndexing_punctuated_unicodeScalars_Backwards", run_CharIndexing_punctuated_unicodeScalars_Backwards) +addTo(&precommitTests, "CharIndexing_russian_unicodeScalars", run_CharIndexing_russian_unicodeScalars) +addTo(&precommitTests, "CharIndexing_russian_unicodeScalars_Backwards", run_CharIndexing_russian_unicodeScalars_Backwards) +addTo(&precommitTests, "CharIndexing_tweet_unicodeScalars", run_CharIndexing_tweet_unicodeScalars) +addTo(&precommitTests, "CharIndexing_tweet_unicodeScalars_Backwards", run_CharIndexing_tweet_unicodeScalars_Backwards) +addTo(&precommitTests, "CharIndexing_utf16_unicodeScalars", run_CharIndexing_utf16_unicodeScalars) +addTo(&precommitTests, "CharIndexing_utf16_unicodeScalars_Backwards", run_CharIndexing_utf16_unicodeScalars_Backwards) +addTo(&precommitTests, "CharIteration_ascii_unicodeScalars", run_CharIteration_ascii_unicodeScalars) +addTo(&precommitTests, "CharIteration_ascii_unicodeScalars_Backwards", run_CharIteration_ascii_unicodeScalars_Backwards) +addTo(&precommitTests, "CharIteration_chinese_unicodeScalars", run_CharIteration_chinese_unicodeScalars) +addTo(&precommitTests, "CharIteration_chinese_unicodeScalars_Backwards", run_CharIteration_chinese_unicodeScalars_Backwards) +addTo(&precommitTests, "CharIteration_japanese_unicodeScalars", run_CharIteration_japanese_unicodeScalars) +addTo(&precommitTests, "CharIteration_japanese_unicodeScalars_Backwards", run_CharIteration_japanese_unicodeScalars_Backwards) +addTo(&precommitTests, "CharIteration_korean_unicodeScalars", run_CharIteration_korean_unicodeScalars) +addTo(&precommitTests, "CharIteration_korean_unicodeScalars_Backwards", run_CharIteration_korean_unicodeScalars_Backwards) +addTo(&precommitTests, "CharIteration_punctuatedJapanese_unicodeScalars", run_CharIteration_punctuatedJapanese_unicodeScalars) +addTo(&precommitTests, "CharIteration_punctuatedJapanese_unicodeScalars_Backwards", run_CharIteration_punctuatedJapanese_unicodeScalars_Backwards) +addTo(&precommitTests, "CharIteration_punctuated_unicodeScalars", run_CharIteration_punctuated_unicodeScalars) +addTo(&precommitTests, "CharIteration_punctuated_unicodeScalars_Backwards", run_CharIteration_punctuated_unicodeScalars_Backwards) +addTo(&precommitTests, "CharIteration_russian_unicodeScalars", run_CharIteration_russian_unicodeScalars) +addTo(&precommitTests, "CharIteration_russian_unicodeScalars_Backwards", run_CharIteration_russian_unicodeScalars_Backwards) +addTo(&precommitTests, "CharIteration_tweet_unicodeScalars", run_CharIteration_tweet_unicodeScalars) +addTo(&precommitTests, "CharIteration_tweet_unicodeScalars_Backwards", run_CharIteration_tweet_unicodeScalars_Backwards) +addTo(&precommitTests, "CharIteration_utf16_unicodeScalars", run_CharIteration_utf16_unicodeScalars) +addTo(&precommitTests, "CharIteration_utf16_unicodeScalars_Backwards", run_CharIteration_utf16_unicodeScalars_Backwards) addTo(&precommitTests, "CharacterLiteralsLarge", run_CharacterLiteralsLarge) addTo(&precommitTests, "CharacterLiteralsSmall", run_CharacterLiteralsSmall) addTo(&precommitTests, "Chars", run_Chars) @@ -237,7 +272,6 @@ addTo(&precommitTests, "EqualSubstringString", run_EqualSubstringString) addTo(&precommitTests, "EqualSubstringSubstring", run_EqualSubstringSubstring) addTo(&precommitTests, "EqualSubstringSubstringGenericEquatable", run_EqualSubstringSubstringGenericEquatable) addTo(&precommitTests, "ErrorHandling", run_ErrorHandling) -addTo(&precommitTests, "GlobalClass", run_GlobalClass) addTo(&precommitTests, "Hanoi", run_Hanoi) addTo(&precommitTests, "HashTest", run_HashTest) addTo(&precommitTests, "Histogram", run_Histogram) @@ -537,6 +571,14 @@ addTo(&stringTests, "StringWalk_korean_characters", run_StringWalk_korean_charac addTo(&stringTests, "StringWalk_korean_characters_Backwards", run_StringWalk_korean_characters_Backwards) addTo(&stringTests, "StringWalk_korean_unicodeScalars", run_StringWalk_korean_unicodeScalars) addTo(&stringTests, "StringWalk_korean_unicodeScalars_Backwards", run_StringWalk_korean_unicodeScalars_Backwards) +addTo(&stringTests, "StringWalk_punctuatedJapanese_characters", run_StringWalk_punctuatedJapanese_characters) +addTo(&stringTests, "StringWalk_punctuatedJapanese_characters_Backwards", run_StringWalk_punctuatedJapanese_characters_Backwards) +addTo(&stringTests, "StringWalk_punctuatedJapanese_unicodeScalars", run_StringWalk_punctuatedJapanese_unicodeScalars) +addTo(&stringTests, "StringWalk_punctuatedJapanese_unicodeScalars_Backwards", run_StringWalk_punctuatedJapanese_unicodeScalars_Backwards) +addTo(&stringTests, "StringWalk_punctuated_characters", run_StringWalk_punctuated_characters) +addTo(&stringTests, "StringWalk_punctuated_characters_Backwards", run_StringWalk_punctuated_characters_Backwards) +addTo(&stringTests, "StringWalk_punctuated_unicodeScalars", run_StringWalk_punctuated_unicodeScalars) +addTo(&stringTests, "StringWalk_punctuated_unicodeScalars_Backwards", run_StringWalk_punctuated_unicodeScalars_Backwards) addTo(&stringTests, "StringWalk_russian_characters", run_StringWalk_russian_characters) addTo(&stringTests, "StringWalk_russian_characters_Backwards", run_StringWalk_russian_characters_Backwards) addTo(&stringTests, "StringWalk_russian_unicodeScalars", run_StringWalk_russian_unicodeScalars) diff --git a/bindings/xml/comment-xml-schema.rng b/bindings/xml/comment-xml-schema.rng index 33fce49ef0c..e077c7ccbb9 100644 --- a/bindings/xml/comment-xml-schema.rng +++ b/bindings/xml/comment-xml-schema.rng @@ -46,6 +46,9 @@ + + + @@ -115,6 +118,9 @@ + + + @@ -166,6 +172,9 @@ + + + @@ -209,6 +218,9 @@ + + + @@ -252,6 +264,9 @@ + + + @@ -294,6 +309,9 @@ + + + @@ -337,6 +355,9 @@ + + + @@ -640,6 +661,16 @@ + + + + + + + + + + diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake index 56b45e92b4b..052213d35d9 100644 --- a/cmake/modules/AddSwift.cmake +++ b/cmake/modules/AddSwift.cmake @@ -2124,3 +2124,8 @@ function(add_swift_host_tool executable) endif() endif() endfunction() + +macro(add_swift_tool_symlink name dest component) + add_llvm_tool_symlink(${name} ${dest} ALWAYS_GENERATE) + llvm_install_symlink(${name} ${dest} ALWAYS_GENERATE COMPONENT ${component}) +endmacro() diff --git a/cmake/modules/DarwinSDKs.cmake b/cmake/modules/DarwinSDKs.cmake index d1cf7e806d9..8e680e603ad 100644 --- a/cmake/modules/DarwinSDKs.cmake +++ b/cmake/modules/DarwinSDKs.cmake @@ -25,7 +25,7 @@ is_sdk_requested(IOS_SIMULATOR swift_build_ios_simulator) if(swift_build_ios_simulator) configure_sdk_darwin( IOS_SIMULATOR "iOS Simulator" "${SWIFT_DARWIN_DEPLOYMENT_VERSION_IOS}" - iphonesimulator ios-simulator ios "x86_64") + iphonesimulator ios-simulator ios "i386;x86_64") configure_target_variant( IOS_SIMULATOR-DA "iOS Debug+Asserts" IOS_SIMULATOR DA "Debug+Asserts") configure_target_variant( diff --git a/cmake/modules/SwiftSource.cmake b/cmake/modules/SwiftSource.cmake index 736cb5a0558..aa525d3c1d6 100644 --- a/cmake/modules/SwiftSource.cmake +++ b/cmake/modules/SwiftSource.cmake @@ -59,9 +59,6 @@ function(handle_swift_sources if (NOT SWIFTSOURCES_IS_MAIN) list(APPEND swift_compile_flags "-module-link-name" "${name}") endif() - if("${SWIFTSOURCES_SDK}" STREQUAL "CYGWIN") - list(APPEND swift_compile_flags -DCYGWIN) - endif() if(swift_sources) compute_library_subdir(SWIFTSOURCES_LIBRARY_SUBDIR @@ -475,7 +472,7 @@ function(_compile_swift_files OUTPUT ${standard_outputs} DEPENDS ${swift_compiler_tool_dep} - ${source_files} ${SWIFTFILE_DEPENDS} + ${file_path} ${source_files} ${SWIFTFILE_DEPENDS} ${swift_ide_test_dependency} ${api_notes_dependency_target} ${obj_dirs_dependency_target} COMMENT "Compiling ${first_output}") diff --git a/docs/Lexicon.rst b/docs/Lexicon.rst index 5a4f6031915..07de796f3e0 100644 --- a/docs/Lexicon.rst +++ b/docs/Lexicon.rst @@ -65,6 +65,9 @@ source code, tests, and commit messages. See also the `LLVM lexicon`_. bitcode Serialized LLVM `IR`. + build czar + Apple term for "the person assigned to watch CI this week". + canonical SIL SIL after the `mandatory passes ` have run. diff --git a/docs/Runtime.md b/docs/Runtime.md index 2da081396fb..6d62b460b77 100644 --- a/docs/Runtime.md +++ b/docs/Runtime.md @@ -71,6 +71,7 @@ Rename with a non-`stdlib` naming scheme. ``` 000000000001cb30 T _swift_allocBox +000000000001cb30 T _swift_allocEmptyBox 000000000001c990 T _swift_allocObject 000000000001ca60 T _swift_bufferAllocate 000000000001ca90 T _swift_bufferHeaderSize diff --git a/docs/tools/swift.pod b/docs/tools/swift.pod index 5a77e20a55a..853815d2588 100644 --- a/docs/tools/swift.pod +++ b/docs/tools/swift.pod @@ -1,30 +1,106 @@ =pod +=encoding utf8 + =head1 NAME -swift - the amazingly new programming language +swift -- Safe, fast, and expressive general-purpose programming language =head1 SYNOPSIS -B [-help] [I [I]] +To invoke the Swift REPL (Read-Eval-Print-Loop): -B [B<-emit-object>|B<-emit-assembly>|B<-emit-library>] - [-help] - B<-o> I - I +=over -The full list of supported options is available via "swift -help" or "swiftc -help". +B + +=back + +To execute a Swift program: + +=over + +B program.swift -- + +=back + +To work with the Swift Package Manager: + +=over + +B build|package|run|test [options] + +=back + +To invoke the Swift compiler: + +=over + +B [options] + +=back + +A list of supported options is available through the "-help" option: + +=over + +B -help + +B build -help + +B -help + +=back =head1 DESCRIPTION -B is a new, high performance systems programming language. It has a clean -and modern syntax, and offers seamless access to existing C and Objective-C code -and frameworks, and is memory safe (by default). +Swift is a general-purpose programming language built using a modern approach to +safety, performance, and software design patterns. -Although inspired by Objective-C and many other languages, Swift is not itself a -C-derived language. As a complete and independent language, Swift packages core -features like flow control, data structures, and functions, with high-level -constructs like objects, protocols, closures, and generics. Swift embraces -modules, eliminating the need for headers and the code duplication they entail. +The goal of the Swift project is to create the best available language for uses +ranging from systems programming, to mobile and desktop apps, scaling up to +cloud services. Most importantly, Swift is designed to make writing and +maintaining I programs easier for the developer. To achieve this goal, +we believe that the most obvious way to write Swift code must also be: -=cut +B The most obvious way to write code should also behave in a safe manner. +Undefined behavior is the enemy of safety, and developer mistakes should be +caught before software is in production. Opting for safety sometimes means Swift +will feel strict, but we believe that clarity saves time in the long run. + +B Swift is intended as a replacement for C-based languages (C, C++, and +Objective-C). As such, Swift must be comparable to those languages in +performance for most tasks. Performance must also be predictable and consistent, +not just fast in short bursts that require clean-up later. There are lots of +languages with novel features — being fast is rare. + +B Swift benefits from decades of advancement in computer science to +offer syntax that is a joy to use, with modern features developers expect. But +Swift is never done. We will monitor language advancements and embrace what +works, continually evolving to make Swift even better. + +=head1 BUGS + +Reporting bugs is a great way for anyone to help improve Swift. +The bug tracker for Swift, an open-source project, is located at +L. + +If a bug can be reproduced only within an Xcode project or a playground, or if +the bug is associated with an Apple NDA, please file a report to Apple’s +bug reporter at L instead. + +=head1 SEE ALSO + +=head2 HOME PAGE + +L + +=head2 APPLE DEVELOPER RESOURCES + +L + +=head2 CODE REPOSITORIES + +Swift Programming Language at L + +Swift Package Manager at L diff --git a/include/swift/ABI/KeyPath.h b/include/swift/ABI/KeyPath.h index 3155c119fa3..199598da634 100644 --- a/include/swift/ABI/KeyPath.h +++ b/include/swift/ABI/KeyPath.h @@ -104,11 +104,11 @@ public: } constexpr static KeyPathComponentHeader - forStructComponentWithUnresolvedOffset() { + forStructComponentWithUnresolvedFieldOffset() { return KeyPathComponentHeader( (_SwiftKeyPathComponentHeader_StructTag << _SwiftKeyPathComponentHeader_DiscriminatorShift) - | _SwiftKeyPathComponentHeader_UnresolvedOffsetPayload); + | _SwiftKeyPathComponentHeader_UnresolvedFieldOffsetPayload); } constexpr static KeyPathComponentHeader @@ -128,11 +128,19 @@ public: } constexpr static KeyPathComponentHeader - forClassComponentWithUnresolvedOffset() { + forClassComponentWithUnresolvedFieldOffset() { return KeyPathComponentHeader( - (_SwiftKeyPathComponentHeader_StructTag + (_SwiftKeyPathComponentHeader_ClassTag << _SwiftKeyPathComponentHeader_DiscriminatorShift) - | _SwiftKeyPathComponentHeader_UnresolvedOffsetPayload); + | _SwiftKeyPathComponentHeader_UnresolvedFieldOffsetPayload); + } + + constexpr static KeyPathComponentHeader + forClassComponentWithUnresolvedIndirectOffset() { + return KeyPathComponentHeader( + (_SwiftKeyPathComponentHeader_ClassTag + << _SwiftKeyPathComponentHeader_DiscriminatorShift) + | _SwiftKeyPathComponentHeader_UnresolvedIndirectOffsetPayload); } constexpr static KeyPathComponentHeader @@ -165,14 +173,13 @@ public: enum ComputedPropertyIDKind { Pointer, - StoredPropertyOffset, + StoredPropertyIndex, VTableOffset, }; constexpr static uint32_t getResolutionStrategy(ComputedPropertyIDKind idKind) { return idKind == Pointer ? _SwiftKeyPathComponentHeader_ComputedIDUnresolvedIndirectPointer - : idKind == StoredPropertyOffset ? _SwiftKeyPathComponentHeader_ComputedIDUnresolvedFieldOffset : (assert("no resolution strategy implemented" && false), 0); } @@ -188,7 +195,7 @@ public: ? _SwiftKeyPathComponentHeader_ComputedSettableFlag : 0) | (kind == SettableMutating ? _SwiftKeyPathComponentHeader_ComputedMutatingFlag : 0) - | (idKind == StoredPropertyOffset + | (idKind == StoredPropertyIndex ? _SwiftKeyPathComponentHeader_ComputedIDByStoredPropertyFlag : 0) | (idKind == VTableOffset ? _SwiftKeyPathComponentHeader_ComputedIDByVTableOffsetFlag : 0) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 3691dede714..8609243eb35 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -44,6 +44,7 @@ namespace swift { class GenericEnvironment; class ArchetypeType; class ASTContext; + struct ASTNode; class ASTPrinter; class ASTWalker; class ConstructorDecl; @@ -2027,34 +2028,33 @@ public: } }; -/// IfConfigDecl - This class represents the declaration-side representation of -/// #if/#else/#endif blocks. Active and inactive block members are stored -/// separately, with the intention being that active members will be handed -/// back to the enclosing declaration. +/// IfConfigDecl - This class represents #if/#else/#endif blocks. +/// Active and inactive block members are stored separately, with the intention +/// being that active members will be handed back to the enclosing context. class IfConfigDecl : public Decl { /// An array of clauses controlling each of the #if/#elseif/#else conditions. /// The array is ASTContext allocated. - ArrayRef> Clauses; + ArrayRef Clauses; SourceLoc EndLoc; public: - IfConfigDecl(DeclContext *Parent, ArrayRef> Clauses, + IfConfigDecl(DeclContext *Parent, ArrayRef Clauses, SourceLoc EndLoc, bool HadMissingEnd) : Decl(DeclKind::IfConfig, Parent), Clauses(Clauses), EndLoc(EndLoc) { IfConfigDeclBits.HadMissingEnd = HadMissingEnd; } - ArrayRef> getClauses() const { return Clauses; } + ArrayRef getClauses() const { return Clauses; } /// Return the active clause, or null if there is no active one. - const IfConfigClause *getActiveClause() const { + const IfConfigClause *getActiveClause() const { for (auto &Clause : Clauses) if (Clause.isActive) return &Clause; return nullptr; } - const ArrayRef getActiveMembers() const { + const ArrayRef getActiveClauseElements() const { if (auto *Clause = getActiveClause()) return Clause->Elements; return {}; @@ -2121,15 +2121,8 @@ public: } bool hasName() const { return bool(Name); } - /// TODO: Rename to getSimpleName? - Identifier getName() const { return Name.getBaseName(); } bool isOperator() const { return Name.isOperator(); } - /// Returns the string for the base name, or "_" if this is unnamed. - StringRef getNameStr() const { - return hasName() ? getName().str() : "_"; - } - /// Retrieve the full name of the declaration. /// TODO: Rename to getName? DeclName getFullName() const { return Name; } @@ -2356,6 +2349,14 @@ protected: } public: + Identifier getName() const { return getFullName().getBaseIdentifier(); } + + /// Returns the string for the base name, or "_" if this is unnamed. + StringRef getNameStr() const { + assert(!getFullName().isSpecial() && "Cannot get string for special names"); + return hasName() ? getBaseName().getIdentifier().str() : "_"; + } + /// The type of this declaration's values. For the type of the /// declaration itself, use getInterfaceType(), which returns a /// metatype. @@ -4097,6 +4098,10 @@ public: FuncDecl *getAccessorFunction(AccessorKind accessor) const; + /// \brief Push all of the accessor functions associated with this VarDecl + /// onto `decls`. + void getAllAccessorFunctions(SmallVectorImpl &decls) const; + /// \brief Turn this into a computed variable, providing a getter and setter. void makeComputed(SourceLoc LBraceLoc, FuncDecl *Get, FuncDecl *Set, FuncDecl *MaterializeForSet, SourceLoc RBraceLoc); @@ -4348,6 +4353,14 @@ public: SourceRange getSourceRange() const; + Identifier getName() const { return getFullName().getBaseIdentifier(); } + + /// Returns the string for the base name, or "_" if this is unnamed. + StringRef getNameStr() const { + assert(!getFullName().isSpecial() && "Cannot get string for special names"); + return hasName() ? getBaseName().getIdentifier().str() : "_"; + } + TypeLoc &getTypeLoc() { return typeLoc; } TypeLoc getTypeLoc() const { return typeLoc; } @@ -4817,6 +4830,14 @@ protected: } public: + Identifier getName() const { return getFullName().getBaseIdentifier(); } + + /// Returns the string for the base name, or "_" if this is unnamed. + StringRef getNameStr() const { + assert(!getFullName().isSpecial() && "Cannot get string for special names"); + return hasName() ? getBaseName().getIdentifier().str() : "_"; + } + /// \brief Should this declaration be treated as if annotated with transparent /// attribute. bool isTransparent() const; @@ -5446,6 +5467,14 @@ public: EnumElementDeclBits.HasArgumentType = HasArgumentType; } + Identifier getName() const { return getFullName().getBaseIdentifier(); } + + /// Returns the string for the base name, or "_" if this is unnamed. + StringRef getNameStr() const { + assert(!getFullName().isSpecial() && "Cannot get string for special names"); + return hasName() ? getBaseName().getIdentifier().str() : "_"; + } + /// \returns false if there was an error during the computation rendering the /// EnumElementDecl invalid, true otherwise. bool computeType(); diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def index f7c0ebd56b9..b3d227b46a4 100644 --- a/include/swift/AST/DiagnosticsFrontend.def +++ b/include/swift/AST/DiagnosticsFrontend.def @@ -187,9 +187,9 @@ ERROR(invalid_conditional_compilation_flag,none, "conditional compilation flags must be valid Swift identifiers (rather than '%0')", (StringRef)) -ERROR(cannot_assign_value_to_conditional_compilation_flag,none, - "conditional compilation flags do not have values in Swift; they are either present or absent" - " (rather than '%0')", (StringRef)) +WARNING(cannot_assign_value_to_conditional_compilation_flag,none, + "conditional compilation flags do not have values in Swift; they are " + "either present or absent (rather than '%0')", (StringRef)) #ifndef DIAG_NO_UNDEF # if defined(DIAG) diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index 0b02cf9849b..350beb458a1 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -182,6 +182,9 @@ ERROR(expected_decl,none, "expected declaration", ()) ERROR(expected_identifier_in_decl,none, "expected identifier in %0 declaration", (StringRef)) +ERROR(number_cant_start_decl_name,none, + "%0 name can only start with a letter or underscore, not a number", + (StringRef)) ERROR(expected_identifier_after_case_comma,none, "expected identifier after comma in enum 'case' declaration", ()) ERROR(decl_redefinition,none, @@ -1418,7 +1421,8 @@ WARNING(swift3_where_inside_brackets,none, "'where' clause next to generic parameters is deprecated " "and will be removed in the future version of Swift", ()) ERROR(where_inside_brackets,none, - "'where' clause next to generic parameters is obsoleted", ()) + "'where' clause next to generic parameters is obsolete, " + "must be written following the declaration's type", ()) //------------------------------------------------------------------------------ // Conditional compilation parsing diagnostics diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 1b9ecdb116c..649cf2a87b6 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -267,6 +267,18 @@ ERROR(incorrect_explicit_closure_result,none, "declared closure result %0 is incompatible with contextual type %1", (Type, Type)) +// FIXME: make this an error when we've fixed the Dispatch problem. +WARNING(err_noescape_param_call,none, + "passing a %select{|closure which captures a }1non-escaping function " + "parameter %0 to a call to a non-escaping function parameter can allow " + "re-entrant modification of a variable", + (DeclName, unsigned)) +WARNING(warn_noescape_param_call,none, + "passing a %select{|closure which captures a }1non-escaping function " + "parameter %0 to a call to a non-escaping function parameter can allow " + "re-entrant modification of a variable and will be illegal in Swift 4", + (DeclName, unsigned)) + ERROR(cannot_call_function_value,none, "cannot invoke value of function type with argument list '%0'", (StringRef)) @@ -897,6 +909,10 @@ ERROR(member_shadows_global_function,none, "use of %0 refers to %1 %2 rather than %3 %4 in %5 %6", (DeclName, DescriptiveDeclKind, DeclName, DescriptiveDeclKind, DeclName, DescriptiveDeclKind, DeclName)) +ERROR(member_shadows_global_function_near_match,none, + "use of %0 nearly matches %3 %4 in %5 %6 rather than %1 %2", + (DeclName, DescriptiveDeclKind, DeclName, DescriptiveDeclKind, DeclName, + DescriptiveDeclKind, DeclName)) ERROR(instance_member_use_on_type,none, "instance member %1 cannot be used on type %0; " @@ -1194,7 +1210,8 @@ ERROR(pattern_type_access,none, "%select{%select{variable|constant}0|property}1 " "%select{must be declared %select{" "%select{private|fileprivate|internal|%error|%error}3|private or fileprivate}4" - "|cannot be declared %select{%error|fileprivate|internal|public|open}3}2 " + "|cannot be declared " + "%select{in this context|fileprivate|internal|public|open}3}2 " "because its type uses " "%select{a private|a fileprivate|an internal|%error|%error}5 type", (bool, bool, bool, Accessibility, bool, Accessibility)) @@ -1209,7 +1226,8 @@ ERROR(pattern_type_access_inferred,none, "%select{%select{variable|constant}0|property}1 " "%select{must be declared %select{" "%select{private|fileprivate|internal|%error|%error}3|private or fileprivate}4" - "|cannot be declared %select{%error|fileprivate|internal|public|open}3}2 " + "|cannot be declared " + "%select{in this context|fileprivate|internal|public|open}3}2 " "because its type %6 uses " "%select{a private|a fileprivate|an internal|%error|%error}5 type", (bool, bool, bool, Accessibility, bool, Accessibility, Type)) @@ -1261,14 +1279,16 @@ ERROR(unsupported_nested_protocol,none, ERROR(type_alias_underlying_type_access,none, "type alias %select{must be declared %select{" "%select{private|fileprivate|internal|%error|%error}2|private or fileprivate}3" - "|cannot be declared %select{%error|fileprivate|internal|public|open}1}0 " + "|cannot be declared " + "%select{in this context|fileprivate|internal|public|open}1}0 " "because its underlying type uses " "%select{a private|a fileprivate|an internal|%error|%error}2 type", (bool, Accessibility, Accessibility, bool)) WARNING(type_alias_underlying_type_access_warn,none, "type alias %select{should be declared " "%select{private|fileprivate|internal|%error|%error}2" - "|should not be declared %select{%error|fileprivate|internal|public|open}1}0 " + "|should not be declared " + "%select{in this context|fileprivate|internal|public|open}1}0 " "because its underlying type uses " "%select{a private|a fileprivate|an internal|%error|%error}2 type", (bool, Accessibility, Accessibility, bool)) @@ -1277,7 +1297,8 @@ WARNING(type_alias_underlying_type_access_warn,none, ERROR(subscript_type_access,none, "subscript %select{must be declared " "%select{private|fileprivate|internal|%error|%error}1" - "|cannot be declared %select{%error|fileprivate|internal|public|open}1}0 " + "|cannot be declared " + "%select{in this context|fileprivate|internal|public|open}1}0 " "because its %select{index|element type}3 uses " "%select{a private|a fileprivate|an internal|%error|%error}2 type", (bool, Accessibility, Accessibility, bool)) @@ -1294,7 +1315,8 @@ ERROR(function_type_access,none, "%select{function|method|initializer}4 " "%select{must be declared %select{" "%select{private|fileprivate|internal|%error|%error}1|private or fileprivate}2" - "|cannot be declared %select{%error|fileprivate|internal|public|open}1}0 " + "|cannot be declared " + "%select{in this context|fileprivate|internal|public|open}1}0 " "because its %select{parameter|result}5 uses " "%select{a private|a fileprivate|an internal|%error|%error}3 type", (bool, Accessibility, bool, Accessibility, unsigned, bool)) @@ -1329,9 +1351,6 @@ ERROR(extension_constrained_inheritance,none, "inheritance clause", (Type)) ERROR(extension_protocol_inheritance,none, "extension of protocol %0 cannot have an inheritance clause", (Type)) -ERROR(extension_protocol_via_typealias,none, - "protocol %0 in the module being compiled cannot be extended via a " - "type alias", (Type)) ERROR(objc_generic_extension_using_type_parameter,none, "extension of a generic Objective-C class cannot access the class's " "generic parameters at runtime", ()) @@ -1414,11 +1433,6 @@ ERROR(witness_self_same_type,none, " (in protocol %5) due to same-type requirement involving 'Self'", (DescriptiveDeclKind, DeclName, Type, DescriptiveDeclKind, DeclName, Type)) -WARNING(witness_self_same_type_warn,none, - "%0 %1 in non-final class %2 cannot be used to satisfy requirement %3 %4" - " (in protocol %5) due to same-type requirement involving 'Self'", - (DescriptiveDeclKind, DeclName, Type, DescriptiveDeclKind, - DeclName, Type)) NOTE(witness_self_weaken_same_type,none, "consider weakening the same-type requirement %0 == %1 to a superclass " "requirement", (Type, Type)) @@ -1452,8 +1466,9 @@ ERROR(protocol_refine_access,none, "%select{protocol must be declared %select{" "%select{private|fileprivate|internal|%error|%error}2" "|private or fileprivate}3 because it refines" - "|%select{%error|fileprivate|internal|public|%error}1 protocol cannot " - "refine}0 %select{a private|a fileprivate|an internal|%error|%error}2 protocol", + "|%select{in this context|fileprivate|internal|public|%error}1 " + "protocol cannot refine}0 " + "%select{a private|a fileprivate|an internal|%error|%error}2 protocol", (bool, Accessibility, Accessibility, bool)) WARNING(protocol_refine_access_warn,none, "%select{protocol should be declared " @@ -1492,7 +1507,8 @@ NOTE(default_associated_type_req_fail,none, (Type, DeclName, Type, Type, bool)) ERROR(associated_type_access,none, "associated type in " - "%select{%error|a fileprivate|an internal|a public|%error}0 protocol uses " + "%select{a private|a fileprivate|an internal|a public|%error}0 protocol " + "uses " "%select{a private|a fileprivate|an internal|%error|%error}1 type in its " "%select{default definition|requirement}2 ", (Accessibility, Accessibility, unsigned)) @@ -1668,9 +1684,6 @@ ERROR(requires_generic_param_same_type_does_not_conform,none, (Type, Identifier)) ERROR(requires_same_concrete_type,none, "generic signature requires types %0 and %1 to be the same", (Type, Type)) -ERROR(protocol_typealias_conflict, none, - "type alias %0 requires types %1 and %2 to be the same", - (Identifier, Type, Type)) WARNING(redundant_conformance_constraint,none, "redundant conformance constraint %0: %1", (Type, ProtocolDecl *)) NOTE(redundant_conformance_here,none, @@ -1678,6 +1691,9 @@ NOTE(redundant_conformance_here,none, "inferred from type here}0", (unsigned, Type, ProtocolDecl *)) +ERROR(same_type_conflict,none, + "%select{generic parameter |protocol |}0%1 cannot be equal to both " + "%2 and %3", (unsigned, Type, Type, Type)) WARNING(redundant_same_type_to_concrete,none, "redundant same-type constraint %0 == %1", (Type, Type)) NOTE(same_type_redundancy_here,none, @@ -1718,11 +1734,15 @@ WARNING(inherited_associated_type_redecl,none, WARNING(typealias_override_associated_type,none, "typealias overriding associated type %0 from protocol %1 is better " "expressed as same-type constraint on the protocol", (DeclName, Type)) +WARNING(associated_type_override_typealias,none, + "associated type %0 is redundant with type %0 declared in inherited " + "%1 %2", (DeclName, DescriptiveDeclKind, Type)) ERROR(generic_param_access,none, "%0 %select{must be declared %select{" "%select{private|fileprivate|internal|%error|%error}3|private or fileprivate}4" - "|cannot be declared %select{%error|fileprivate|internal|public|open}2}1 " + "|cannot be declared " + "%select{in this context|fileprivate|internal|public|open}2}1 " "because its generic %select{parameter|requirement}5 uses " "%select{a private|a fileprivate|an internal|%error|%error}3 type", (DescriptiveDeclKind, bool, Accessibility, Accessibility, bool, bool)) @@ -1944,7 +1964,7 @@ WARNING(class_inherits_anyobject,none, // Enums ERROR(enum_case_access,none, - "enum case in %select{%error|a fileprivate|an internal|a public|%error}0 enum " + "enum case in %select{a private|a fileprivate|an internal|a public|%error}0 enum " "uses %select{a private|a fileprivate|an internal|%error|%error}1 type", (Accessibility, Accessibility)) WARNING(enum_case_access_warn,none, @@ -1975,7 +1995,8 @@ NOTE(enum_declares_rawrep_with_raw_type,none, ERROR(enum_raw_type_access,none, "enum %select{must be declared %select{" "%select{private|fileprivate|internal|%error|%error}2|private or fileprivate}3" - "|cannot be declared %select{%error|fileprivate|internal|public|open}1}0 " + "|cannot be declared " + "%select{in this context|fileprivate|internal|public|open}1}0 " "because its raw type uses " "%select{a private|a fileprivate|an internal|%error|%error}2 type", (bool, Accessibility, Accessibility, bool)) @@ -2044,7 +2065,7 @@ ERROR(broken_decodable_requirement,none, "Decodable protocol is broken: unexpected requirement", ()) NOTE(codable_extraneous_codingkey_case_here,none, - "CodingKey case %0 does match any stored properties", (Identifier)) + "CodingKey case %0 does not match any stored properties", (Identifier)) NOTE(codable_non_conforming_property_here,none, "cannot automatically synthesize %0 because %1 does not conform to %0", (Type, Type)) NOTE(codable_non_decoded_property_here,none, @@ -2696,9 +2717,6 @@ NOTE(silence_optional_in_interpolation_segment_call,none, ERROR(invalid_noescape_use,none, "non-escaping %select{value|parameter}1 %0 may only be called", (Identifier, bool)) -NOTE(noescape_autoclosure,none, - "parameter %0 is implicitly non-escaping because it was declared @autoclosure", - (Identifier)) NOTE(noescape_parameter,none, "parameter %0 is implicitly non-escaping", (Identifier)) @@ -3026,7 +3044,8 @@ ERROR(bool_intrinsics_not_found,none, ERROR(class_super_access,none, "class %select{must be declared %select{" "%select{private|fileprivate|internal|%error|%error}2|private or fileprivate}3" - "|cannot be declared %select{%error|fileprivate|internal|public|open}1}0 " + "|cannot be declared " + "%select{in this context|fileprivate|internal|public|open}1}0 " "because its superclass is " "%select{private|fileprivate|internal|%error|%error}2", (bool, Accessibility, Accessibility, bool)) @@ -3597,6 +3616,9 @@ ERROR(resilience_decl_unavailable, #undef FRAGILE_FUNC_KIND NOTE(resilience_decl_declared_here, + none, "%0 %1 is not public", (DescriptiveDeclKind, DeclName)) + +NOTE(resilience_decl_declared_here_versioned, none, "%0 %1 is not '@_versioned' or public", (DescriptiveDeclKind, DeclName)) ERROR(designated_init_in_extension_resilient,none, diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index a3d6d1b5416..947721b2724 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -1076,10 +1076,6 @@ public: llvm_unreachable("bad Kind"); } - bool isDSOHandle() const { - return getKind() == DSOHandle; - } - SourceRange getSourceRange() const { return Loc; } // For a magic identifier that produces a string literal, retrieve the @@ -2858,9 +2854,11 @@ public: SourceIsScalar_t isSourceScalar, ConcreteDeclRef defaultArgsOwner, ArrayRef VariadicArgs, - MutableArrayRef CallerDefaultArgs, Type ty) + Type VarargsArrayTy, + MutableArrayRef CallerDefaultArgs, + Type ty) : ImplicitConversionExpr(ExprKind::TupleShuffle, subExpr, ty), - ElementMapping(elementMapping), VarargsArrayTy(), + ElementMapping(elementMapping), VarargsArrayTy(VarargsArrayTy), DefaultArgsOwner(defaultArgsOwner), VariadicArgs(VariadicArgs), CallerDefaultArgs(CallerDefaultArgs) { @@ -2876,8 +2874,6 @@ public: /// single-element tuple for the purposes of interpreting behavior. bool isSourceScalar() const { return TupleShuffleExprBits.IsSourceScalar; } - /// Set the varargs array type to use. - void setVarargsArrayType(Type T) { VarargsArrayTy = T; } Type getVarargsArrayType() const { assert(!VarargsArrayTy.isNull()); return VarargsArrayTy; diff --git a/include/swift/AST/GenericSignatureBuilder.h b/include/swift/AST/GenericSignatureBuilder.h index f44ad76962d..0f81c8507cf 100644 --- a/include/swift/AST/GenericSignatureBuilder.h +++ b/include/swift/AST/GenericSignatureBuilder.h @@ -23,6 +23,7 @@ #include "swift/AST/Decl.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/Identifier.h" +#include "swift/AST/ProtocolConformanceRef.h" #include "swift/AST/Types.h" #include "swift/AST/TypeLoc.h" #include "swift/AST/TypeRepr.h" @@ -74,6 +75,11 @@ enum class ArchetypeResolutionKind { /// Only create a new potential archetype to describe this dependent type /// if it is already known. AlreadyKnown, + + /// Only create a potential archetype when it is well-formed (i.e., we know + /// that there is a nested type with that name), but (unlike \c AlreadyKnown) + /// allow the creation of a new potential archetype. + WellFormed, }; /// \brief Collects a set of requirements of generic parameters, both explicitly @@ -176,6 +182,9 @@ public: /// the concrete type. unsigned recursiveConcreteType : 1; + /// Whether we have an invalid concrete type. + unsigned invalidConcreteType : 1; + /// Whether we have detected recursion during the substitution of /// the superclass type. unsigned recursiveSuperclassType : 1; @@ -265,6 +274,10 @@ private: GenericSignatureBuilder(const GenericSignatureBuilder &) = delete; GenericSignatureBuilder &operator=(const GenericSignatureBuilder &) = delete; + /// Record that the given potential archetype is unresolved, so we know to + /// resolve it later. + void recordUnresolvedType(PotentialArchetype *unresolvedPA); + /// When a particular requirement cannot be resolved due to, e.g., a /// currently-unresolvable or nested type, this routine should be /// called to cope with the unresolved requirement. @@ -277,6 +290,15 @@ private: FloatingRequirementSource source, UnresolvedHandlingKind unresolvedHandling); + /// Resolve the conformance of the given potential archetype to + /// the given protocol when the potential archetype is known to be equivalent + /// to a concrete type. + /// + /// \returns the requirement source for the resolved conformance, or nullptr + /// if the conformance could not be resolved. + const RequirementSource *resolveConcreteConformance(PotentialArchetype *pa, + ProtocolDecl *proto); + /// Retrieve the constraint source conformance for the superclass constraint /// of the given potential archetype (if present) to the given protocol. /// @@ -284,9 +306,8 @@ private: /// queried. /// /// \param proto The protocol to which we are establishing conformance. - const RequirementSource *resolveSuperConformance( - GenericSignatureBuilder::PotentialArchetype *pa, - ProtocolDecl *proto); + const RequirementSource *resolveSuperConformance(PotentialArchetype *pa, + ProtocolDecl *proto); /// \brief Add a new conformance requirement specifying that the given /// potential archetype conforms to the given protocol. @@ -294,6 +315,10 @@ private: ProtocolDecl *Proto, const RequirementSource *Source); + /// Try to resolve the given unresolved potential archetype. + ConstraintResult resolveUnresolvedType(PotentialArchetype *pa, + bool allowTypoCorrection); + public: /// \brief Add a new same-type requirement between two fully resolved types /// (output of \c GenericSignatureBuilder::resolve). @@ -308,15 +333,6 @@ public: FloatingRequirementSource Source, llvm::function_ref diagnoseMismatch); - /// \brief Add a new same-type requirement between two fully resolved types - /// (output of GenericSignatureBuilder::resolve). - /// - /// The two types must not be incompatible concrete types. - ConstraintResult addSameTypeRequirementDirect( - ResolvedType paOrT1, - ResolvedType paOrT2, - FloatingRequirementSource Source); - /// \brief Add a new same-type requirement between two unresolved types. /// /// The types are resolved with \c GenericSignatureBuilder::resolve, and must @@ -722,6 +738,16 @@ public: /// \c TypeRepr. Inferred, + /// A requirement inferred from part of the signature of a declaration + /// but for which we don't want to produce warnings, e.g., the result + /// type of a generic function: + /// + /// func f() -> Set { ... } // infers T: Hashable, but don't warn + /// + /// This is a root requirement source, which can be described by a + /// \c TypeRepr. + QuietlyInferred, + /// A requirement for the creation of the requirement signature of a /// protocol. /// @@ -752,7 +778,7 @@ public: /// A requirement that was resolved via a superclass requirement. /// - /// This stores the \c ProtocolConformance* used to resolve the + /// This stores the \c ProtocolConformanceRef used to resolve the /// requirement. Superclass, @@ -766,6 +792,10 @@ public: /// This stores the \c ProtocolConformance* used to resolve the /// requirement. Concrete, + + /// A requirement that was resolved based on structural derivation from + /// another requirement. + Derived, }; /// The kind of requirement source. @@ -774,6 +804,7 @@ public: private: /// The kind of storage we have. enum class StorageKind : uint8_t { + None, RootArchetype, StoredType, ProtocolConformance, @@ -798,7 +829,7 @@ private: TypeBase *type; /// A protocol conformance used to satisfy the requirement. - ProtocolConformance *conformance; + void *conformance; /// An associated type to which a requirement is being applied. AssociatedTypeDecl *assocType; @@ -816,10 +847,12 @@ private: case Explicit: case Inferred: + case QuietlyInferred: case NestedTypeNameMatch: case Superclass: case Parent: case Concrete: + case Derived: return 0; } @@ -853,6 +886,7 @@ private: switch (kind) { case Explicit: case Inferred: + case QuietlyInferred: case RequirementSignatureSelf: case NestedTypeNameMatch: return true; @@ -862,6 +896,7 @@ private: case Superclass: case Parent: case Concrete: + case Derived: return false; } @@ -911,7 +946,7 @@ public: } RequirementSource(Kind kind, const RequirementSource *parent, - ProtocolConformance *conformance) + ProtocolConformanceRef conformance) : kind(kind), storageKind(StorageKind::ProtocolConformance), hasTrailingWrittenRequirementLoc(false), usesRequirementSignature(false), parent(parent) { @@ -920,7 +955,7 @@ public: assert(isAcceptableStorageKind(kind, storageKind) && "RequirementSource kind/storageKind mismatch"); - storage.conformance = conformance; + storage.conformance = conformance.getOpaqueValue(); } RequirementSource(Kind kind, const RequirementSource *parent, @@ -936,6 +971,16 @@ public: storage.assocType = assocType; } + RequirementSource(Kind kind, const RequirementSource *parent) + : kind(kind), storageKind(StorageKind::None), + hasTrailingWrittenRequirementLoc(false), + usesRequirementSignature(false), parent(parent) { + assert((static_cast(parent) != isRootKind(kind)) && + "Root RequirementSource should not have parent (or vice versa)"); + assert(isAcceptableStorageKind(kind, storageKind) && + "RequirementSource kind/storageKind mismatch"); + } + public: /// Retrieve an abstract requirement source. static const RequirementSource *forAbstract(PotentialArchetype *root); @@ -949,7 +994,8 @@ public: /// inferred from some part of a generic declaration's signature, e.g., the /// parameter or result type of a generic function. static const RequirementSource *forInferred(PotentialArchetype *root, - const TypeRepr *typeRepr); + const TypeRepr *typeRepr, + bool quietly); /// Retrieve a requirement source representing the requirement signature /// computation for a protocol. @@ -976,13 +1022,14 @@ public: /// A requirement source that describes that a requirement that is resolved /// via a superclass requirement. const RequirementSource *viaSuperclass( - GenericSignatureBuilder &builder, - ProtocolConformance *conformance) const; + GenericSignatureBuilder &builder, + ProtocolConformanceRef conformance) const; /// A requirement source that describes that a requirement that is resolved /// via a same-type-to-concrete requirement. - const RequirementSource *viaConcrete(GenericSignatureBuilder &builder, - ProtocolConformance *conformance) const; + const RequirementSource *viaConcrete( + GenericSignatureBuilder &builder, + ProtocolConformanceRef conformance) const; /// A constraint source that describes that a constraint that is resolved /// for a nested type via a constraint on its parent. @@ -991,6 +1038,10 @@ public: const RequirementSource *viaParent(GenericSignatureBuilder &builder, AssociatedTypeDecl *assocType) const; + /// A constraint source that describes a constraint that is structurally + /// derived from another constraint but does not require further information. + const RequirementSource *viaDerived(GenericSignatureBuilder &builder) const; + /// Retrieve the root requirement source. const RequirementSource *getRoot() const; @@ -1021,7 +1072,7 @@ public: /// Whether the requirement is inferred or derived from an inferred /// requirement. - bool isInferredRequirement() const; + bool isInferredRequirement(bool includeQuietInferred) const; /// Classify the kind of this source for diagnostic purposes. unsigned classifyDiagKind() const; @@ -1079,9 +1130,9 @@ public: ProtocolDecl *getProtocolDecl() const; /// Retrieve the protocol conformance for this requirement, if there is one. - ProtocolConformance *getProtocolConformance() const { - if (storageKind != StorageKind::ProtocolConformance) return nullptr; - return storage.conformance; + ProtocolConformanceRef getProtocolConformance() const { + assert(storageKind == StorageKind::ProtocolConformance); + return ProtocolConformanceRef::getFromOpaqueValue(storage.conformance); } /// Retrieve the associated type declaration for this requirement, if there @@ -1135,6 +1186,8 @@ class GenericSignatureBuilder::FloatingRequirementSource { Explicit, /// An inferred requirement source lacking a root. Inferred, + /// A quietly inferred requirement source lacking a root. + QuietlyInferred, /// A requirement source augmented by an abstract protocol requirement AbstractProtocol, /// A requirement source for a nested-type-name match introduced by @@ -1180,8 +1233,9 @@ public: return { Explicit, requirementRepr }; } - static FloatingRequirementSource forInferred(const TypeRepr *typeRepr) { - return { Inferred, typeRepr }; + static FloatingRequirementSource forInferred(const TypeRepr *typeRepr, + bool quietly) { + return { quietly? QuietlyInferred : Inferred, typeRepr }; } static FloatingRequirementSource viaProtocolRequirement( @@ -1325,13 +1379,7 @@ class GenericSignatureBuilder::PotentialArchetype { /// \brief Construct a new potential archetype for an unresolved /// associated type. - PotentialArchetype(PotentialArchetype *parent, Identifier name) - : parentOrBuilder(parent), identifier(name), isUnresolvedNestedType(true), - IsRecursive(false), Invalid(false), - DiagnosedRename(false) - { - assert(parent != nullptr && "Not an associated type?"); - } + PotentialArchetype(PotentialArchetype *parent, Identifier name); /// \brief Construct a new potential archetype for an associated type. PotentialArchetype(PotentialArchetype *parent, AssociatedTypeDecl *assocType) @@ -1548,6 +1596,7 @@ public: /// \brief Retrieve (or create) a nested type with the given name. PotentialArchetype *getNestedType(Identifier Name, + ArchetypeResolutionKind kind, GenericSignatureBuilder &builder); /// \brief Retrieve (or create) a nested type with a known associated type. @@ -1559,18 +1608,6 @@ public: PotentialArchetype *getNestedType(TypeDecl *concreteDecl, GenericSignatureBuilder &builder); - /// Describes the kind of update that is performed. - enum class NestedTypeUpdate { - /// Resolve an existing potential archetype, but don't create a new - /// one if not present. - ResolveExisting, - /// If this potential archetype is missing, create it. - AddIfMissing, - /// If this potential archetype is missing and would be a better anchor, - /// create it. - AddIfBetterAnchor, - }; - /// \brief Retrieve (or create) a nested type that is the current best /// nested archetype anchor (locally) with the given name. /// @@ -1579,7 +1616,7 @@ public: PotentialArchetype *getNestedArchetypeAnchor( Identifier name, GenericSignatureBuilder &builder, - NestedTypeUpdate kind = NestedTypeUpdate::AddIfMissing); + ArchetypeResolutionKind kind); /// Update the named nested type when we know this type conforms to the given /// protocol. @@ -1589,7 +1626,7 @@ public: /// a potential archetype should not be created if it's missing. PotentialArchetype *updateNestedTypeForConformance( PointerUnion type, - NestedTypeUpdate kind); + ArchetypeResolutionKind kind); /// Update the named nested type when we know this type conforms to the given /// protocol. @@ -1600,7 +1637,7 @@ public: PotentialArchetype *updateNestedTypeForConformance( Identifier name, ProtocolDecl *protocol, - NestedTypeUpdate kind); + ArchetypeResolutionKind kind); /// \brief Retrieve (or build) the type corresponding to the potential /// archetype within the given generic environment. @@ -1678,7 +1715,22 @@ public: /// Describes a requirement whose processing has been delayed for some reason. class GenericSignatureBuilder::DelayedRequirement { public: - RequirementKind kind; + enum Kind { + /// A type requirement, which may be a conformance or a superclass + /// requirement. + Type, + + /// A layout requirement. + Layout, + + /// A same-type requirement. + SameType, + + /// An unresolved potential archetype. + Unresolved, + }; + + Kind kind; UnresolvedType lhs; RequirementRHS rhs; FloatingRequirementSource source; diff --git a/include/swift/AST/Identifier.h b/include/swift/AST/Identifier.h index 9e85dcf6e6d..40da25fecc0 100644 --- a/include/swift/AST/Identifier.h +++ b/include/swift/AST/Identifier.h @@ -233,6 +233,14 @@ public: return !isSpecial() && getIdentifier().isEditorPlaceholder(); } + /// A representation of the name to be displayed to users. May be ambiguous + /// between identifiers and special names. + StringRef userFacingName() const { + if (empty()) + return "_"; + return getIdentifier().str(); + } + int compare(DeclBaseName other) const { // TODO: Sort special names cleverly return getIdentifier().compare(other.getIdentifier()); @@ -250,11 +258,6 @@ public: return Ident.get() < RHS.Ident.get(); } - // TODO: Remove once migration to DeclBaseName has been completed - operator Identifier() { - return getIdentifier(); - } - const void *getAsOpaquePointer() const { return Ident.get(); } static DeclBaseName getFromOpaquePointer(void *P) { diff --git a/include/swift/AST/IfConfigClause.h b/include/swift/AST/IfConfigClause.h index 7c8c1cf44d2..a3ce67401db 100644 --- a/include/swift/AST/IfConfigClause.h +++ b/include/swift/AST/IfConfigClause.h @@ -22,11 +22,11 @@ namespace swift { class Expr; class SourceLoc; + struct ASTNode; /// This represents one part of a #if block. If the condition field is /// non-null, then this represents a #if or a #elseif, otherwise it represents /// an #else block. -template struct IfConfigClause { /// The location of the #if, #elseif, or #else keyword. SourceLoc Loc; @@ -36,13 +36,13 @@ struct IfConfigClause { Expr *Cond; /// Elements inside the clause - ArrayRef Elements; + ArrayRef Elements; /// True if this is the active clause of the #if block. bool isActive; - IfConfigClause(SourceLoc Loc, Expr *Cond, - ArrayRef Elements, bool isActive) + IfConfigClause(SourceLoc Loc, Expr *Cond, + ArrayRef Elements, bool isActive) : Loc(Loc), Cond(Cond), Elements(Elements), isActive(isActive) { } }; diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h index 634419d14e1..3b6b5e3f911 100644 --- a/include/swift/AST/Module.h +++ b/include/swift/AST/Module.h @@ -209,9 +209,6 @@ private: unsigned ResilienceStrategy : 2; } Flags; - /// The magic __dso_handle variable. - VarDecl *DSOHandle; - ModuleDecl(Identifier name, ASTContext &ctx); public: diff --git a/include/swift/AST/PrintOptions.h b/include/swift/AST/PrintOptions.h index b91170692ca..2d528f4375b 100644 --- a/include/swift/AST/PrintOptions.h +++ b/include/swift/AST/PrintOptions.h @@ -279,7 +279,7 @@ struct PrintOptions { /// Print all decls that have at least this level of access. Accessibility AccessibilityFilter = Accessibility::Private; - /// Print IfConfigDecls and IfConfigStmts. + /// Print IfConfigDecls. bool PrintIfConfig = true; /// Whether we are printing for sil. diff --git a/include/swift/AST/ProtocolConformance.h b/include/swift/AST/ProtocolConformance.h index 8959548f15f..37d81e52111 100644 --- a/include/swift/AST/ProtocolConformance.h +++ b/include/swift/AST/ProtocolConformance.h @@ -397,7 +397,7 @@ public: AbstractStorageDecl *getBehaviorDecl() const { return ContextAndInvalid.getPointer().dyn_cast(); } - + /// Retrieve the type witness and type decl (if one exists) /// for the given associated type. std::pair diff --git a/include/swift/AST/SILOptions.h b/include/swift/AST/SILOptions.h index aa2f890a1f8..e6c7fbc2543 100644 --- a/include/swift/AST/SILOptions.h +++ b/include/swift/AST/SILOptions.h @@ -145,6 +145,17 @@ public: /// \brief Enable large loadable types IRGen pass. bool EnableLargeLoadableTypes = false; + /// Enables the "fully fragile" resilience strategy. + /// + /// \see ResilienceStrategy::Fragile + bool SILSerializeAll = false; + + /// If set, SIL witness tables will be serialized. + /// + /// It is supposed to be used only for compiling overlays. + /// User code should never be compiled with this flag set. + bool SILSerializeWitnessTables = false; + SILOptions() : Sanitize(SanitizerKind::None) {} /// Return a hash code of any components from these options that should diff --git a/include/swift/AST/Stmt.h b/include/swift/AST/Stmt.h index fe6ca397a8d..9b090702ae2 100644 --- a/include/swift/AST/Stmt.h +++ b/include/swift/AST/Stmt.h @@ -655,46 +655,6 @@ public: static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Guard; } }; -/// IfConfigStmt - This class models the statement-side representation of -/// #if/#else/#endif blocks. -class IfConfigStmt : public Stmt { - /// An array of clauses controlling each of the #if/#elseif/#else conditions. - /// The array is ASTContext allocated. - ArrayRef> Clauses; - SourceLoc EndLoc; - bool HadMissingEnd; - -public: - IfConfigStmt(ArrayRef> Clauses, SourceLoc EndLoc, - bool HadMissingEnd) - : Stmt(StmtKind::IfConfig, /*implicit=*/false), - Clauses(Clauses), EndLoc(EndLoc), HadMissingEnd(HadMissingEnd) {} - - SourceLoc getIfLoc() const { return Clauses[0].Loc; } - - SourceLoc getStartLoc() const { return getIfLoc(); } - SourceLoc getEndLoc() const { return EndLoc; } - - bool hadMissingEnd() const { return HadMissingEnd; } - - const ArrayRef> &getClauses() const { - return Clauses; - } - - ArrayRef getActiveClauseElements() const { - for (auto &Clause : Clauses) - if (Clause.isActive) - return Clause.Elements; - return ArrayRef(); - } - - // Implement isa/cast/dyncast/etc. - static bool classof(const Stmt *S) { - return S->getKind() == StmtKind::IfConfig; - } -}; - - /// WhileStmt - while statement. After type-checking, the condition is of /// type Builtin.Int1. class WhileStmt : public LabeledConditionalStmt { @@ -972,7 +932,7 @@ public: /// Switch statement. class SwitchStmt final : public LabeledStmt, - private llvm::TrailingObjects { + private llvm::TrailingObjects { friend TrailingObjects; SourceLoc SwitchLoc, LBraceLoc, RBraceLoc; @@ -993,7 +953,7 @@ public: static SwitchStmt *create(LabeledStmtInfo LabelInfo, SourceLoc SwitchLoc, Expr *SubjectExpr, SourceLoc LBraceLoc, - ArrayRef Cases, + ArrayRef Cases, SourceLoc RBraceLoc, ASTContext &C); @@ -1012,10 +972,28 @@ public: /// Get the subject expression of the switch. Expr *getSubjectExpr() const { return SubjectExpr; } void setSubjectExpr(Expr *e) { SubjectExpr = e; } + + ArrayRef getRawCases() const { + return {getTrailingObjects(), CaseCount}; + } + +private: + struct AsCaseStmtWithSkippingIfConfig { + AsCaseStmtWithSkippingIfConfig() {} + Optional operator()(const ASTNode &N) const { + if (auto *CS = llvm::dyn_cast_or_null(N.dyn_cast())) + return CS; + return None; + } + }; + +public: + using AsCaseStmtRange = OptionalTransformRange, + AsCaseStmtWithSkippingIfConfig>; /// Get the list of case clauses. - ArrayRef getCases() const { - return {getTrailingObjects(), CaseCount}; + AsCaseStmtRange getCases() const { + return AsCaseStmtRange(getRawCases(), AsCaseStmtWithSkippingIfConfig()); } static bool classof(const Stmt *S) { diff --git a/include/swift/AST/StmtNodes.def b/include/swift/AST/StmtNodes.def index 301f636c219..6c718acd157 100644 --- a/include/swift/AST/StmtNodes.def +++ b/include/swift/AST/StmtNodes.def @@ -61,7 +61,6 @@ STMT(Catch, Stmt) STMT(Break, Stmt) STMT(Continue, Stmt) STMT(Fallthrough, Stmt) -STMT(IfConfig, Stmt) STMT(Fail, Stmt) STMT(Throw, Stmt) diff --git a/include/swift/AST/TypeRepr.h b/include/swift/AST/TypeRepr.h index 804e677ccf4..b38ba96b130 100644 --- a/include/swift/AST/TypeRepr.h +++ b/include/swift/AST/TypeRepr.h @@ -63,9 +63,11 @@ class alignas(8) TypeRepr { class TupleTypeReprBitfields { friend class TupleTypeRepr; unsigned : NumTypeReprBits; - // HasNames, HasLabels? - unsigned NameStatus : 2; - // Whether this tuple has '...' and its position. + + /// The number of elements contained. + unsigned NumElements : 16; + + /// Whether this tuple has '...' and its position. unsigned HasEllipsis : 1; }; @@ -572,6 +574,22 @@ private: friend class TypeRepr; }; +/// \brief A parsed element within a tuple type. +struct TupleTypeReprElement { + Identifier Name; + SourceLoc NameLoc; + Identifier SecondName; + SourceLoc SecondNameLoc; + SourceLoc UnderscoreLoc; + SourceLoc ColonLoc; + SourceLoc InOutLoc; + TypeRepr *Type; + SourceLoc TrailingCommaLoc; + + TupleTypeReprElement() {} + TupleTypeReprElement(TypeRepr *Type): Type(Type) {} +}; + /// \brief A tuple type. /// \code /// (Foo, Bar) @@ -579,121 +597,113 @@ private: /// (_ x: Foo) /// \endcode class TupleTypeRepr final : public TypeRepr, - private llvm::TrailingObjects> { + private llvm::TrailingObjects> { friend TrailingObjects; typedef std::pair SourceLocAndIdx; - unsigned NumElements; SourceRange Parens; - - enum { - NotNamed = 0, - HasNames = 1, - HasLabels = 2 - }; - size_t numTrailingObjects(OverloadToken) const { - return NumElements; - } - size_t numTrailingObjects(OverloadToken) const { - return TupleTypeReprBits.NameStatus >= HasNames ? NumElements : 0; - } - size_t numTrailingObjects(OverloadToken) const { - switch (TupleTypeReprBits.NameStatus) { - case NotNamed: return 0; - case HasNames: return NumElements; - case HasLabels: return NumElements + NumElements; - } - llvm_unreachable("all cases should have been handled"); + size_t numTrailingObjects(OverloadToken) const { + return TupleTypeReprBits.NumElements; } - TupleTypeRepr(ArrayRef Elements, SourceRange Parens, - ArrayRef ElementNames, - ArrayRef ElementNameLocs, - ArrayRef underscoreLocs, - SourceLoc Ellipsis, unsigned EllipsisIdx); + TupleTypeRepr(ArrayRef Elements, + SourceRange Parens, SourceLoc Ellipsis, unsigned EllipsisIdx); + public: - - unsigned getNumElements() const { return NumElements; } + unsigned getNumElements() const { return TupleTypeReprBits.NumElements; } bool hasElementNames() const { - return TupleTypeReprBits.NameStatus >= HasNames; - } - bool hasUnderscoreLocs() const { - return TupleTypeReprBits.NameStatus == HasLabels; + for (auto &Element : getElements()) { + if (Element.NameLoc.isValid()) { + return true; + } + } + return false; } - ArrayRef getElements() const { - return { getTrailingObjects(), NumElements }; + ArrayRef getElements() const { + return { getTrailingObjects(), + TupleTypeReprBits.NumElements }; } - ArrayRef getElementNames() const { - if (!hasElementNames()) return {}; - return { getTrailingObjects(), NumElements }; + void getElementTypes(SmallVectorImpl &Types) const { + for (auto &Element : getElements()) { + Types.push_back(Element.Type); + } } - ArrayRef getElementNameLocs() const { - if (!hasElementNames()) return {}; - return { getTrailingObjects(), NumElements }; + TypeRepr *getElementType(unsigned i) const { + return getElement(i).Type; } - ArrayRef getUnderscoreLocs() const { - if (!hasUnderscoreLocs()) return {}; - return { getTrailingObjects() + NumElements, NumElements }; + TupleTypeReprElement getElement(unsigned i) const { + return getElements()[i]; } - TypeRepr *getElement(unsigned i) const { return getElements()[i]; } + void getElementNames(SmallVectorImpl &Names) { + for (auto &Element : getElements()) { + Names.push_back(Element.Name); + } + } Identifier getElementName(unsigned i) const { - return hasElementNames() ? getElementNames()[i] : Identifier(); + return getElement(i).Name; } SourceLoc getElementNameLoc(unsigned i) const { - return hasElementNames() ? getElementNameLocs()[i] : SourceLoc(); + return getElement(i).NameLoc; } SourceLoc getUnderscoreLoc(unsigned i) const { - return hasElementNames() ? getElementNameLocs()[i] : SourceLoc(); + return getElement(i).UnderscoreLoc; } bool isNamedParameter(unsigned i) const { - return hasUnderscoreLocs() ? getUnderscoreLocs()[i].isValid() : false; + return getUnderscoreLoc(i).isValid(); } SourceRange getParens() const { return Parens; } - bool hasEllipsis() const { return TupleTypeReprBits.HasEllipsis; } + bool hasEllipsis() const { + return TupleTypeReprBits.HasEllipsis; + } + SourceLoc getEllipsisLoc() const { return hasEllipsis() ? getTrailingObjects()[0].first : SourceLoc(); } + unsigned getEllipsisIndex() const { return hasEllipsis() ? - getTrailingObjects()[0].second : NumElements; + getTrailingObjects()[0].second : + TupleTypeReprBits.NumElements; } + void removeEllipsis() { if (hasEllipsis()) { TupleTypeReprBits.HasEllipsis = false; - getTrailingObjects()[0] = {SourceLoc(), NumElements}; + getTrailingObjects()[0] = { + SourceLoc(), + getNumElements() + }; } } bool isParenType() const { - return NumElements == 1 && getElementNameLoc(0).isInvalid() && + return TupleTypeReprBits.NumElements == 1 && + getElementNameLoc(0).isInvalid() && !hasEllipsis(); } static TupleTypeRepr *create(const ASTContext &C, - ArrayRef Elements, + ArrayRef Elements, SourceRange Parens, - ArrayRef ElementNames, - ArrayRef ElementNameLocs, - ArrayRef underscoreLocs, SourceLoc Ellipsis, unsigned EllipsisIdx); static TupleTypeRepr *create(const ASTContext &C, - ArrayRef Elements, + ArrayRef Elements, SourceRange Parens) { - return create(C, Elements, Parens, {}, {}, {}, + return create(C, Elements, Parens, SourceLoc(), Elements.size()); } static TupleTypeRepr *createEmpty(const ASTContext &C, SourceRange Parens); diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 0b9feceaa18..b6c20d8de83 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -45,6 +45,7 @@ namespace swift { class AssociatedTypeDecl; class ASTContext; class ClassDecl; + class DependentMemberType; class GenericTypeParamDecl; class GenericTypeParamType; class GenericParamList; @@ -534,6 +535,12 @@ public: return getRecursiveProperties().hasTypeParameter(); } + /// Find any unresolved dependent member type within this type. + /// + /// "Unresolved" dependent member types have no known associated type, + /// and are only used transiently in the type checker. + const DependentMemberType *findUnresolvedDependentMemberType(); + /// Return the root generic parameter of this type parameter type. GenericTypeParamType *getRootGenericParam(); @@ -1378,12 +1385,13 @@ public: /// escaping. class ParameterTypeFlags { enum ParameterFlags : uint8_t { - None = 0, - Variadic = 1 << 0, + None = 0, + Variadic = 1 << 0, AutoClosure = 1 << 1, - Escaping = 1 << 2, - - NumBits = 3 + Escaping = 1 << 2, + InOut = 1 << 3, + + NumBits = 4 }; OptionSet value; static_assert(NumBits < 8*sizeof(OptionSet), "overflowed"); @@ -1393,10 +1401,11 @@ class ParameterTypeFlags { public: ParameterTypeFlags() = default; - ParameterTypeFlags(bool variadic, bool autoclosure, bool escaping) + ParameterTypeFlags(bool variadic, bool autoclosure, bool escaping, bool inOut) : value((variadic ? Variadic : 0) | (autoclosure ? AutoClosure : 0) | - (escaping ? Escaping : 0)) {} + (escaping ? Escaping : 0) | + (inOut ? InOut : 0)) {} /// Create one from what's present in the parameter type inline static ParameterTypeFlags fromParameterType(Type paramTy, @@ -1406,12 +1415,18 @@ public: bool isVariadic() const { return value.contains(Variadic); } bool isAutoClosure() const { return value.contains(AutoClosure); } bool isEscaping() const { return value.contains(Escaping); } - + bool isInOut() const { return value.contains(InOut); } + ParameterTypeFlags withEscaping(bool escaping) const { return ParameterTypeFlags(escaping ? value | ParameterTypeFlags::Escaping : value - ParameterTypeFlags::Escaping); } + ParameterTypeFlags withInOut(bool isInout) const { + return ParameterTypeFlags(isInout ? value | ParameterTypeFlags::InOut + : value - ParameterTypeFlags::InOut); + } + bool operator ==(const ParameterTypeFlags &other) const { return value.toRaw() == other.value.toRaw(); } @@ -1460,24 +1475,16 @@ class TupleTypeElt { ParameterTypeFlags Flags; friend class TupleType; - + public: TupleTypeElt() = default; - inline /*implicit*/ TupleTypeElt(Type ty, Identifier name, - bool isVariadic, bool isAutoClosure, - bool isEscaping); - TupleTypeElt(Type ty, Identifier name = Identifier(), - ParameterTypeFlags PTFlags = {}) - : Name(name), ElementType(ty), Flags(PTFlags) {} - - /*implicit*/ TupleTypeElt(TypeBase *Ty) - : Name(Identifier()), ElementType(Ty), Flags() { } - + ParameterTypeFlags fl = {}); + bool hasName() const { return !Name.empty(); } Identifier getName() const { return Name; } - Type getType() const { return ElementType.getPointer(); } + Type getType() const { return ElementType; } ParameterTypeFlags getParameterFlags() const { return Flags; } @@ -1489,16 +1496,14 @@ public: /// Determine whether this field is an escaping parameter closure. bool isEscaping() const { return Flags.isEscaping(); } - - static inline Type getVarargBaseTy(Type VarArgT); - + + /// Determine whether this field is marked 'inout'. + bool isInOut() const { return Flags.isInOut(); } + /// Remove the type of this varargs element designator, without the array /// type wrapping it. - Type getVarargBaseTy() const { - assert(isVararg()); - return getVarargBaseTy(getType()); - } - + Type getVarargBaseTy() const; + /// Retrieve a copy of this tuple type element with the type replaced. TupleTypeElt getWithType(Type T) const { return TupleTypeElt(T, getName(), getParameterFlags()); @@ -2297,10 +2302,55 @@ getSILFunctionLanguage(SILFunctionTypeRepresentation rep) { class AnyFunctionType : public TypeBase { const Type Input; const Type Output; - + const unsigned NumParams; + public: using Representation = FunctionTypeRepresentation; + class Param { + public: + explicit Param(Type t) : Ty(t), Label(Identifier()), Flags() {} + explicit Param(const TupleTypeElt &tte) + : Ty(tte.isVararg() ? tte.getVarargBaseTy() : tte.getType()), + Label(tte.getName()), Flags(tte.getParameterFlags()) {} + explicit Param(Type t, Identifier l, ParameterTypeFlags f) + : Ty(t), Label(l), Flags(f) {} + + private: + /// The type of the parameter. For a variadic parameter, this is the + /// element type. + Type Ty; + + // The label associated with the parameter, if any. + Identifier Label; + + /// Parameter specific flags. + ParameterTypeFlags Flags = {}; + + public: + Type getType() const { return Ty; } + CanType getCanType() const { + assert(Ty->isCanonical()); + return CanType(Ty); + } + + Identifier getLabel() const { return Label; } + + ParameterTypeFlags getParameterFlags() const { return Flags; } + + /// Whether the parameter is varargs + bool isVariadic() const { return Flags.isVariadic(); } + + /// Whether the parameter is marked '@autoclosure' + bool isAutoClosure() const { return Flags.isAutoClosure(); } + + /// Whether the parameter is marked '@escaping' + bool isEscaping() const { return Flags.isEscaping(); } + + /// Whether the parameter is marked 'inout' + bool isInOut() const { return Flags.isInOut(); } + }; + /// \brief A class which abstracts out some details necessary for /// making a call. class ExtInfo { @@ -2442,16 +2492,29 @@ public: protected: AnyFunctionType(TypeKind Kind, const ASTContext *CanTypeContext, Type Input, Type Output, RecursiveTypeProperties properties, - const ExtInfo &Info) - : TypeBase(Kind, CanTypeContext, properties), Input(Input), Output(Output) { + unsigned NumParams, const ExtInfo &Info) + : TypeBase(Kind, CanTypeContext, properties), Input(Input), Output(Output), + NumParams(NumParams) { AnyFunctionTypeBits.ExtInfo = Info.Bits; } public: + /// \brief Break an input type into an array of \c AnyFunctionType::Params. + static void decomposeInput(Type type, + SmallVectorImpl &result); + + /// \brief Take an array of parameters and turn it into an input type. + /// + /// The result type is only there as a way to extract the ASTContext when + /// needed. + static Type composeInput(ASTContext &ctx, ArrayRef params, + bool canonicalVararg); Type getInput() const { return Input; } Type getResult() const { return Output; } - + ArrayRef getParams() const; + unsigned getNumParams() const { return NumParams; } + ExtInfo getExtInfo() const { return ExtInfo(AnyFunctionTypeBits.ExtInfo); } @@ -2477,6 +2540,10 @@ public: return getExtInfo().throws(); } + /// Determine whether the given function input type is one of the + /// canonical forms. + static bool isCanonicalFunctionInputType(Type input); + /// Returns a new function type exactly like this one but with the ExtInfo /// replaced. AnyFunctionType *withExtInfo(ExtInfo info) const; @@ -2489,7 +2556,15 @@ public: }; BEGIN_CAN_TYPE_WRAPPER(AnyFunctionType, Type) typedef AnyFunctionType::ExtInfo ExtInfo; - PROXY_CAN_TYPE_SIMPLE_GETTER(getInput) + + CanType getInput() const { + return getPointer()->getInput()->getCanonicalType(); + } + + ArrayRef getParams() const { + return getPointer()->getParams(); + } + PROXY_CAN_TYPE_SIMPLE_GETTER(getResult) CanAnyFunctionType withExtInfo(ExtInfo info) const { @@ -2501,7 +2576,10 @@ END_CAN_TYPE_WRAPPER(AnyFunctionType, Type) /// /// For example: /// let x : (Float, Int) -> Int -class FunctionType : public AnyFunctionType { +class FunctionType final : public AnyFunctionType, + private llvm::TrailingObjects { + friend TrailingObjects; + public: /// 'Constructor' Factory Function static FunctionType *get(Type Input, Type Result) { @@ -2509,76 +2587,66 @@ public: } static FunctionType *get(Type Input, Type Result, const ExtInfo &Info); + + static FunctionType *get(ArrayRef params, + Type result, const ExtInfo &info, + bool canonicalVararg = false); + // Retrieve the input parameters of this function type. + ArrayRef getParams() const { + return {getTrailingObjects(), getNumParams()}; + } + // Implement isa/cast/dyncast/etc. static bool classof(const TypeBase *T) { return T->getKind() == TypeKind::Function; } - + private: - FunctionType(Type Input, Type Result, + FunctionType(ArrayRef params, + Type Input, Type Result, RecursiveTypeProperties properties, const ExtInfo &Info); }; BEGIN_CAN_TYPE_WRAPPER(FunctionType, AnyFunctionType) static CanFunctionType get(CanType input, CanType result) { - return CanFunctionType(FunctionType::get(input, result)); + return CanFunctionType( + FunctionType::get(input, result) + ->getCanonicalType()->castTo()); } static CanFunctionType get(CanType input, CanType result, const ExtInfo &info) { - return CanFunctionType(FunctionType::get(input, result, info)); + return CanFunctionType( + FunctionType::get(input, result, info) + ->getCanonicalType()->castTo()); } - + static CanFunctionType get(ArrayRef params, + Type result, const ExtInfo &info) { + return CanFunctionType(FunctionType::get(params, result, info, + /*canonicalVararg=*/true)); + } + CanFunctionType withExtInfo(ExtInfo info) const { return CanFunctionType(cast(getPointer()->withExtInfo(info))); } END_CAN_TYPE_WRAPPER(FunctionType, AnyFunctionType) - -/// A call argument or parameter. -struct CallArgParam { - /// The type of the argument or parameter. For a variadic parameter, - /// this is the element type. - Type Ty; - - // The label associated with the argument or parameter, if any. - Identifier Label; - - /// Whether the parameter has a default argument. Not valid for arguments. - bool HasDefaultArgument = false; - - /// Parameter specific flags, not valid for arguments - ParameterTypeFlags parameterFlags = {}; - - /// Whether the argument or parameter has a label. - bool hasLabel() const { return !Label.empty(); } - - /// Whether the parameter is varargs - bool isVariadic() const { return parameterFlags.isVariadic(); } - - /// Whether the parameter is autoclosure - bool isAutoClosure() const { return parameterFlags.isAutoClosure(); } - - /// Whether the parameter is escaping - bool isEscaping() const { return parameterFlags.isEscaping(); } -}; - -/// Break an argument type into an array of \c CallArgParams. + +/// Break an argument type into an array of \c AnyFunctionType::Params. /// /// \param type The type to decompose. /// \param argumentLabels The argument labels to use. -SmallVector +SmallVector decomposeArgType(Type type, ArrayRef argumentLabels); -/// Break a parameter type into an array of \c CallArgParams. -/// -/// \param paramOwner The declaration that owns this parameter. -/// \param level The level of parameters that are being decomposed. -SmallVector -decomposeParamType(Type type, const ValueDecl *paramOwner, unsigned level); - +/// Break the parameter list into an array of booleans describing whether +/// the argument type at each index has a default argument associated with +/// it. +void computeDefaultMap(Type type, const ValueDecl *paramOwner, unsigned level, + SmallVectorImpl &outDefaultMap); + /// Turn a param list into a symbolic and printable representation that does not /// include the types, something like (: , b:, c:) -std::string getParamListAsString(ArrayRef parameters); +std::string getParamListAsString(ArrayRef parameters); /// Describes a generic function type. /// @@ -2587,18 +2655,22 @@ std::string getParamListAsString(ArrayRef parameters); /// on those parameters and dependent member types thereof. The input and /// output types of the generic function can be expressed in terms of those /// generic parameters. -class GenericFunctionType : public AnyFunctionType, - public llvm::FoldingSetNode -{ +class GenericFunctionType final : public AnyFunctionType, + public llvm::FoldingSetNode, + private llvm::TrailingObjects { + friend TrailingObjects; + GenericSignature *Signature; /// Construct a new generic function type. GenericFunctionType(GenericSignature *sig, + ArrayRef params, Type input, Type result, const ExtInfo &info, const ASTContext *ctx, RecursiveTypeProperties properties); + public: /// Create a new generic function type. static GenericFunctionType *get(GenericSignature *sig, @@ -2606,6 +2678,18 @@ public: Type result, const ExtInfo &info); + /// Create a new generic function type. + static GenericFunctionType *get(GenericSignature *sig, + ArrayRef params, + Type result, + const ExtInfo &info, + bool canonicalVararg = false); + + // Retrieve the input parameters of this function type. + ArrayRef getParams() const { + return {getTrailingObjects(), getNumParams()}; + } + /// Retrieve the generic signature of this function type. GenericSignature *getGenericSignature() const { return Signature; @@ -2656,7 +2740,19 @@ BEGIN_CAN_TYPE_WRAPPER(GenericFunctionType, AnyFunctionType) auto fnType = GenericFunctionType::get(sig, input, result, info); return cast(fnType->getCanonicalType()); } - + + /// Create a new generic function type. + static CanGenericFunctionType get(CanGenericSignature sig, + ArrayRef params, + CanType result, + const ExtInfo &info) { + // Knowing that the argument types are independently canonical is + // not sufficient to guarantee that the function type will be canonical. + auto fnType = GenericFunctionType::get(sig, params, result, info, + /*canonicalVararg=*/true); + return cast(fnType->getCanonicalType()); + } + CanGenericSignature getGenericSignature() const { return CanGenericSignature(getPointer()->getGenericSignature()); } @@ -4598,24 +4694,9 @@ inline CanType CanType::getNominalParent() const { return cast(*this).getParent(); } } - -inline TupleTypeElt::TupleTypeElt(Type ty, Identifier name, bool isVariadic, - bool isAutoClosure, bool isEscaping) - : Name(name), ElementType(ty), - Flags(isVariadic, isAutoClosure, isEscaping) { - assert(!isVariadic || - ty->hasError() || - isa(ty.getPointer()) || - (isa(ty.getPointer()) && - ty->castTo()->getGenericArgs().size() == 1)); - assert(!isAutoClosure || (ty->is() && - ty->castTo()->isAutoClosure())); - assert(!isEscaping || (ty->is() && - !ty->castTo()->isNoEscape())); -} - -inline Type TupleTypeElt::getVarargBaseTy(Type VarArgT) { - TypeBase *T = VarArgT.getPointer(); + +inline Type TupleTypeElt::getVarargBaseTy() const { + TypeBase *T = getType().getPointer(); if (auto *AT = dyn_cast(T)) return AT->getBaseType(); if (auto *BGT = dyn_cast(T)) { @@ -4633,7 +4714,8 @@ ParameterTypeFlags::fromParameterType(Type paramTy, bool isVariadic) { paramTy->castTo()->isAutoClosure(); bool escaping = paramTy->is() && !paramTy->castTo()->isNoEscape(); - return {isVariadic, autoclosure, escaping}; + bool inOut = paramTy->is(); + return {isVariadic, autoclosure, escaping, inOut}; } #define TYPE(id, parent) diff --git a/include/swift/Demangling/Demangle.h b/include/swift/Demangling/Demangle.h index 0904510944b..152f49d5790 100644 --- a/include/swift/Demangling/Demangle.h +++ b/include/swift/Demangling/Demangle.h @@ -216,8 +216,21 @@ public: void dump(); }; +/// Returns the length of the swift mangling prefix of the \p SymbolName. +/// +/// Returns 0 if \p SymbolName is not a mangled swift (>= swift 4.x) name. +int getManglingPrefixLength(const char *mangledName); + +/// Returns true if \p SymbolName is a mangled swift name. +/// +/// This does not include the old (<= swift 3.x) mangling prefix "_T". +inline bool isMangledName(llvm::StringRef MangledName) { + return getManglingPrefixLength(MangledName.data()) != 0; +} + /// Returns true if the mangledName starts with the swift mangling prefix. /// +/// This includes the old (<= swift 3.x) mangling prefix "_T". /// \param mangledName A null-terminated string containing a mangled name. bool isSwiftSymbol(const char *mangledName); @@ -252,8 +265,8 @@ public: /// Demangle the given symbol and return the parse tree. /// - /// \param MangledName The mangled symbol string, which start with the - /// mangling prefix _T. + /// \param MangledName The mangled symbol string, which start a mangling + /// prefix: _T, _T0, $S, _$S. /// /// \returns A parse tree for the demangled string - or a null pointer /// on failure. @@ -263,8 +276,8 @@ public: /// Demangle the given type and return the parse tree. /// - /// \param MangledName The mangled type string, which does _not_ start with - /// the mangling prefix _T. + /// \param MangledName The mangled symbol string, which start a mangling + /// prefix: _T, _T0, $S, _$S. /// /// \returns A parse tree for the demangled string - or a null pointer /// on failure. @@ -274,8 +287,8 @@ public: /// Demangle the given symbol and return the readable name. /// - /// \param MangledName The mangled symbol string, which start with the - /// mangling prefix _T. + /// \param MangledName The mangled symbol string, which start a mangling + /// prefix: _T, _T0, $S, _$S. /// /// \returns The demangled string. std::string demangleSymbolAsString(llvm::StringRef MangledName, @@ -284,7 +297,7 @@ public: /// Demangle the given type and return the readable name. /// /// \param MangledName The mangled type string, which does _not_ start with - /// the mangling prefix _T. + /// a mangling prefix. /// /// \returns The demangled string. std::string demangleTypeAsString(llvm::StringRef MangledName, diff --git a/include/swift/Demangling/Demangler.h b/include/swift/Demangling/Demangler.h index 23d9d943b28..a370fb0d469 100644 --- a/include/swift/Demangling/Demangler.h +++ b/include/swift/Demangling/Demangler.h @@ -328,6 +328,12 @@ protected: Pos--; } + StringRef consumeAll() { + StringRef str = Text.drop_front(Pos); + Pos = Text.size(); + return str; + } + void pushNode(NodePointer Nd) { NodeStack.push_back(Nd, *this); } diff --git a/include/swift/Driver/ToolChain.h b/include/swift/Driver/ToolChain.h index abf85b68ae4..3bc2204e03e 100644 --- a/include/swift/Driver/ToolChain.h +++ b/include/swift/Driver/ToolChain.h @@ -168,6 +168,14 @@ public: /// Return the default language type to use for the given extension. virtual types::ID lookupTypeForExtension(StringRef Ext) const; + + /// Check whether a clang library with a given name exists. + /// + /// \param args Invocation arguments. + /// \param sanitizer Sanitizer name. + virtual bool sanitizerRuntimeLibExists(const llvm::opt::ArgList &args, + StringRef sanitizer) const; + }; } // end namespace driver } // end namespace swift diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index 14e036ccabd..021e27bb54d 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -144,6 +144,11 @@ public: /// Intended for debugging purposes only. unsigned WarnLongExpressionTypeChecking = 0; + /// If non-zero, overrides the default threshold for how long we let + /// the expression type checker run before we consider an expression + /// too complex. + unsigned SolverExpressionTimeThreshold = 0; + enum ActionType { NoneAction, ///< No specific action Parse, ///< Parse only @@ -240,11 +245,6 @@ public: /// by the Clang importer as part of semantic analysis. bool SerializeBridgingHeader = false; - /// Enables the "fully fragile" resilience strategy. - /// - /// \see ResilienceStrategy::Fragile - bool SILSerializeAll = false; - /// Indicates whether or not the frontend should print statistics upon /// termination. bool PrintStats = false; diff --git a/include/swift/IDE/DigesterEnums.def b/include/swift/IDE/DigesterEnums.def index 4f44e2a9f48..2b0fc311fa0 100644 --- a/include/swift/IDE/DigesterEnums.def +++ b/include/swift/IDE/DigesterEnums.def @@ -88,6 +88,7 @@ KEY(typeAttributes) KEY(declAttributes) KEY(declKind) KEY(ownership) +KEY(superclassUsr) KNOWN_TYPE(Optional) KNOWN_TYPE(ImplicitlyUnwrappedOptional) diff --git a/include/swift/IDE/Utils.h b/include/swift/IDE/Utils.h index 7054168428f..0691661d68d 100644 --- a/include/swift/IDE/Utils.h +++ b/include/swift/IDE/Utils.h @@ -148,6 +148,7 @@ enum class SemaTokenKind { Invalid, ValueRef, ModuleRef, + ExprStart, StmtStart, }; @@ -164,6 +165,7 @@ struct SemaToken { DeclContext *DC = nullptr; Type ContainerType; Stmt *TrailingStmt = nullptr; + Expr *TrailingExpr = nullptr; SemaToken() = default; SemaToken(ValueDecl *ValueD, TypeDecl *CtorTyRef, ExtensionDecl *ExtTyRef, @@ -175,6 +177,8 @@ struct SemaToken { Mod(Mod), Loc(Loc) { } SemaToken(Stmt *TrailingStmt) : Kind(SemaTokenKind::StmtStart), TrailingStmt(TrailingStmt) {} + SemaToken(Expr* TrailingExpr) : Kind(SemaTokenKind::ExprStart), + TrailingExpr(TrailingExpr) {} bool isValid() const { return !isInvalid(); } bool isInvalid() const { return Kind == SemaTokenKind::Invalid; } }; @@ -191,6 +195,7 @@ public: SourceManager &getSourceMgr() const; private: bool walkToExprPre(Expr *E) override; + bool walkToExprPost(Expr *E) override; bool walkToDeclPre(Decl *D, CharSourceRange Range) override; bool walkToDeclPost(Decl *D) override; bool walkToStmtPre(Stmt *S) override; @@ -211,6 +216,7 @@ private: SourceLoc Loc, bool IsRef, Type Ty = Type()); bool tryResolve(ModuleEntity Mod, SourceLoc Loc); bool tryResolve(Stmt *St); + bool tryResolve(Expr *Exp); bool visitSubscriptReference(ValueDecl *D, CharSourceRange Range, bool IsOpenBracket) override; }; diff --git a/include/swift/Migrator/FixitFilter.h b/include/swift/Migrator/FixitFilter.h index bb52a9f82b8..39ec69ffe68 100644 --- a/include/swift/Migrator/FixitFilter.h +++ b/include/swift/Migrator/FixitFilter.h @@ -113,7 +113,6 @@ struct FixitFilter { Info.ID == diag::parameter_extraneous_double_up.ID || Info.ID == diag::attr_decl_attr_now_on_type.ID || Info.ID == diag::noescape_parameter.ID || - Info.ID == diag::noescape_autoclosure.ID || Info.ID == diag::where_inside_brackets.ID || Info.ID == diag::selector_construction_suggest.ID || Info.ID == diag::selector_literal_deprecated_suggest.ID || diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index b5b0aaf3bed..62926fe3bfa 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -326,6 +326,8 @@ def warn_long_expression_type_checking : Separate<["-"], "warn-long-expression-t def warn_long_expression_type_checking_EQ : Joined<["-"], "warn-long-expression-type-checking=">, Alias; +def solver_expression_time_threshold_EQ : Joined<["-"], "solver-expression-time-threshold=">; + def enable_source_import : Flag<["-"], "enable-source-import">, HelpText<"Enable importing of Swift source files">; @@ -366,6 +368,9 @@ def sil_link_all : Flag<["-"], "sil-link-all">, def sil_serialize_all : Flag<["-"], "sil-serialize-all">, HelpText<"Serialize all generated SIL">; +def sil_serialize_witness_tables : Flag<["-"], "sil-serialize-witness-tables">, + HelpText<"Serialize eligible SIL witness tables">; + def sil_verify_all : Flag<["-"], "sil-verify-all">, HelpText<"Verify SIL after each transform">; diff --git a/include/swift/Option/SanitizerOptions.h b/include/swift/Option/SanitizerOptions.h index 36b0840ced0..f6d23604936 100644 --- a/include/swift/Option/SanitizerOptions.h +++ b/include/swift/Option/SanitizerOptions.h @@ -14,6 +14,8 @@ #define SWIFT_OPTIONS_SANITIZER_OPTIONS_H #include "swift/Basic/Sanitizers.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/Option/Arg.h" // FIXME: This include is just for llvm::SanitizerCoverageOptions. We should @@ -26,10 +28,14 @@ class DiagnosticEngine; /// \brief Parses a -sanitize= argument's values. /// /// \param Diag If non null, the argument is used to diagnose invalid values. +/// \param sanitizerRuntimeLibExists Function which checks for existance of a +// sanitizer dylib with a given name. /// \return Returns a SanitizerKind. -SanitizerKind parseSanitizerArgValues(const llvm::opt::Arg *A, - const llvm::Triple &Triple, - DiagnosticEngine &Diag); +SanitizerKind parseSanitizerArgValues( + const llvm::opt::Arg *A, + const llvm::Triple &Triple, + DiagnosticEngine &Diag, + llvm::function_ref sanitizerRuntimeLibExists); /// \brief Parses a -sanitize-coverage= argument's value. llvm::SanitizerCoverageOptions diff --git a/include/swift/Parse/Lexer.h b/include/swift/Parse/Lexer.h index 4f42ed21560..866f08ebe20 100644 --- a/include/swift/Parse/Lexer.h +++ b/include/swift/Parse/Lexer.h @@ -239,7 +239,7 @@ public: } /// Lex a full token including leading and trailing trivia. - RC fullLex(); + RC fullLex(); bool isKeepingComments() const { return RetainComments == CommentRetentionMode::ReturnAsTokens; diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index bd129a28545..2d7a40cb912 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -716,7 +716,11 @@ public: ParserResult parseDeclAssociatedType(ParseDeclOptions Flags, DeclAttributes &Attributes); - ParserResult parseDeclIfConfig(ParseDeclOptions Flags); + /// Parse a #if ... #endif directive. + /// Delegate callback function to parse elements in the blocks. + ParserResult parseIfConfig( + llvm::function_ref &, bool)> parseElements); + /// Parse a #line/#sourceLocation directive. /// 'isLine = true' indicates parsing #line instead of #sourcelocation ParserStatus parseLineDirective(bool isLine = false); @@ -1265,6 +1269,8 @@ public: // Statement Parsing bool isStartOfStmt(); + bool isTerminatorForBraceItemListKind(BraceItemListKind Kind, + ArrayRef ParsedDecls); ParserResult parseStmt(); ParserStatus parseExprOrStmt(ASTNode &Result); ParserResult parseStmtBreak(); @@ -1277,8 +1283,6 @@ public: ParserResult parseStmtConditionPoundAvailable(); ParserResult parseStmtIf(LabeledStmtInfo LabelInfo); ParserResult parseStmtGuard(); - ParserResult parseStmtIfConfig(BraceItemListKind Kind - = BraceItemListKind::Brace); ParserResult parseStmtWhile(LabeledStmtInfo LabelInfo); ParserResult parseStmtRepeat(LabeledStmtInfo LabelInfo); ParserResult parseStmtDo(LabeledStmtInfo LabelInfo); @@ -1289,7 +1293,8 @@ public: ParserResult parseStmtForEach(SourceLoc ForLoc, LabeledStmtInfo LabelInfo); ParserResult parseStmtSwitch(LabeledStmtInfo LabelInfo); - ParserResult parseStmtCase(); + ParserStatus parseStmtCases(SmallVectorImpl &cases, bool IsActive); + ParserResult parseStmtCase(bool IsActive); //===--------------------------------------------------------------------===// // Generics Parsing diff --git a/include/swift/Runtime/Debug.h b/include/swift/Runtime/Debug.h index d9979a733be..7512d1a8e21 100644 --- a/include/swift/Runtime/Debug.h +++ b/include/swift/Runtime/Debug.h @@ -134,6 +134,82 @@ void dumpStackTraceEntry(unsigned index, void *framePC, LLVM_ATTRIBUTE_NOINLINE void printCurrentBacktrace(unsigned framesToSkip = 1); +/// Debugger breakpoint ABI. This structure is passed to the debugger (and needs +/// to be stable) and describes extra information about a fatal error or a +/// non-fatal warning, which should be logged as a runtime issue. Please keep +/// all integer values pointer-sized. +struct RuntimeErrorDetails { + static const uintptr_t currentVersion = 2; + + // ABI version, needs to be set to "currentVersion". + uintptr_t version; + + // A short hyphenated string describing the type of the issue, e.g. + // "precondition-failed" or "exclusivity-violation". + const char *errorType; + + // Description of the current thread's stack position. + const char *currentStackDescription; + + // Number of frames in the current stack that should be ignored when reporting + // the issue (exluding the reportToDebugger/_swift_runtime_on_report frame). + // The remaining top frame should point to user's code where the bug is. + uintptr_t framesToSkip; + + // Address of some associated object (if there's any). + void *memoryAddress; + + // A structure describing an extra thread (and its stack) that is related. + struct Thread { + const char *description; + uint64_t threadID; + uintptr_t numFrames; + void **frames; + }; + + // Number of extra threads (excluding the current thread) that are related, + // and the pointer to the array of extra threads. + uintptr_t numExtraThreads; + Thread *threads; + + // Describes a suggested fix-it. Text in [startLine:startColumn, + // endLine:endColumn) is to be replaced with replacementText. + struct FixIt { + const char *filename; + uintptr_t startLine; + uintptr_t startColumn; + uintptr_t endLine; + uintptr_t endColumn; + const char *replacementText; + }; + + // Describes some extra information, possible with fix-its, about the current + // runtime issue. + struct Note { + const char *description; + uintptr_t numFixIts; + FixIt *fixIts; + }; + + // Number of suggested fix-its, and the pointer to the array of them. + uintptr_t numFixIts; + FixIt *fixIts; + + // Number of related notes, and the pointer to the array of them. + uintptr_t numNotes; + Note *notes; +}; + +enum: uintptr_t { + RuntimeErrorFlagNone = 0, + RuntimeErrorFlagFatal = 1 << 0 +}; + +/// Debugger hook. Calling this stops the debugger with a message and details +/// about the issues. +void reportToDebugger(uintptr_t flags, const char *message, + RuntimeErrorDetails *details = nullptr); + // namespace swift } diff --git a/include/swift/Runtime/HeapObject.h b/include/swift/Runtime/HeapObject.h index 66d7198f676..b4c1ae08e4b 100644 --- a/include/swift/Runtime/HeapObject.h +++ b/include/swift/Runtime/HeapObject.h @@ -169,6 +169,10 @@ SWIFT_RUNTIME_EXPORT BoxPair::Return swift_makeBoxUnique(OpaqueValue *buffer, Metadata const *type, size_t alignMask); +/// Returns the address of a heap object representing all empty box types. +SWIFT_RUNTIME_EXPORT +HeapObject* swift_allocEmptyBox(); + // Allocate plain old memory. This is the generalized entry point // Never returns nil. The returned memory is uninitialized. // diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h index 9a2d1efe86d..285a911673a 100644 --- a/include/swift/Runtime/Metadata.h +++ b/include/swift/Runtime/Metadata.h @@ -1761,6 +1761,9 @@ struct TargetHeapLocalVariableMetadata static bool classof(const TargetMetadata *metadata) { return metadata->getKind() == MetadataKind::HeapLocalVariable; } + constexpr TargetHeapLocalVariableMetadata() + : TargetHeapMetadata(MetadataKind::HeapLocalVariable), + OffsetToFirstCapture(0), CaptureDescription(nullptr) {} }; using HeapLocalVariableMetadata = TargetHeapLocalVariableMetadata; diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def index 75c885b93b0..8305984ec8d 100644 --- a/include/swift/Runtime/RuntimeFunctions.def +++ b/include/swift/Runtime/RuntimeFunctions.def @@ -73,6 +73,11 @@ FUNCTION(ProjectBox, swift_projectBox, DefaultCC, ARGS(RefCountedPtrTy), ATTRS(NoUnwind, ReadNone)) +FUNCTION(AllocEmptyBox, swift_allocEmptyBox, DefaultCC, + RETURNS(RefCountedPtrTy), + ARGS(), + ATTRS(NoUnwind)) + // RefCounted *swift_allocObject(Metadata *type, size_t size, size_t alignMask); FUNCTION_WITH_GLOBAL_SYMBOL_AND_IMPL(AllocObject, swift_allocObject, _swift_allocObject, _swift_allocObject_, RegisterPreservingCC, diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index 56823d94d0c..f6aa056b81c 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -996,9 +996,7 @@ class ApplyInstBase; // partial specialization for full applies inherits from this. template class ApplyInstBase : public Base { - enum { - Callee - }; + enum { Callee, NumStaticOperands }; /// The type of the callee with our substitutions applied. SILType SubstCalleeType; @@ -1015,7 +1013,7 @@ class ApplyInstBase : public Base { unsigned NumCallArguments; /// The fixed operand is the callee; the rest are arguments. - TailAllocatedOperandList<1> Operands; + TailAllocatedOperandList Operands; Substitution *getSubstitutionsStorage() { return reinterpret_cast(Operands.asArray().end()); @@ -1117,6 +1115,8 @@ public: return {getSubstitutionsStorage(), NumSubstitutions}; } + static unsigned getOperandIndexOfFirstArgument() { return NumStaticOperands; } + /// The arguments passed to this instruction. MutableArrayRef getArgumentOperands() { return Operands.getDynamicAsArray().slice(0, getNumCallArguments()); @@ -1459,6 +1459,11 @@ public: StoredProperty, GettableProperty, SettableProperty, + Last_Packed = SettableProperty, // Last enum value that can be packed in + // a PointerIntPair + OptionalChain, + OptionalForce, + OptionalWrap, }; // The pair of a captured index value and its Hashable conformance for a @@ -1469,40 +1474,63 @@ public: }; private: - // Value is the VarDecl* for StoredProperty, and the SILFunction* of the - // Getter for computed properties - llvm::PointerIntPair ValueAndKind; + static constexpr const unsigned KindPackingBits = 2; + static constexpr const unsigned UnpackedKind = (1u << KindPackingBits) - 1; + static_assert((unsigned)Kind::Last_Packed < UnpackedKind, + "too many kinds to pack"); + + // Value is the VarDecl* for StoredProperty, the SILFunction* of the + // Getter for computed properties, or the Kind for other kinds + llvm::PointerIntPair ValueAndKind; // false if id is a SILFunction*; true if id is a SILDeclRef - llvm::PointerIntPair + llvm::PointerIntPair SetterAndIdKind; ComputedPropertyId::ValueType IdValue; ArrayRef Indices; CanType ComponentType; - + + unsigned kindForPacking(Kind k) { + auto value = (unsigned)k; + assert(value <= (unsigned)Kind::Last_Packed); + return value; + } + + KeyPathPatternComponent(Kind kind, CanType ComponentType) + : ValueAndKind((void*)((uintptr_t)kind << KindPackingBits), UnpackedKind), + ComponentType(ComponentType) + { + assert(kind > Kind::Last_Packed && "wrong initializer"); + } + KeyPathPatternComponent(VarDecl *storedProp, Kind kind, CanType ComponentType) - : ValueAndKind(storedProp, kind), ComponentType(ComponentType) {} + : ValueAndKind(storedProp, kindForPacking(kind)), + ComponentType(ComponentType) {} KeyPathPatternComponent(ComputedPropertyId id, Kind kind, SILFunction *getter, SILFunction *setter, ArrayRef indices, CanType ComponentType) - : ValueAndKind(getter, kind), + : ValueAndKind(getter, kindForPacking(kind)), SetterAndIdKind(setter, id.Kind), IdValue(id.Value), Indices(indices), ComponentType(ComponentType) {} public: - KeyPathPatternComponent() : ValueAndKind(nullptr, (Kind)0) {} + KeyPathPatternComponent() : ValueAndKind(nullptr, 0) {} bool isNull() const { return ValueAndKind.getPointer() == nullptr; } Kind getKind() const { - return ValueAndKind.getInt(); + auto packedKind = ValueAndKind.getInt(); + if (packedKind != UnpackedKind) + return (Kind)packedKind; + return (Kind)((uintptr_t)ValueAndKind.getPointer() >> KindPackingBits); } CanType getComponentType() const { @@ -1515,6 +1543,9 @@ public: return static_cast(ValueAndKind.getPointer()); case Kind::GettableProperty: case Kind::SettableProperty: + case Kind::OptionalChain: + case Kind::OptionalForce: + case Kind::OptionalWrap: llvm_unreachable("not a stored property"); } llvm_unreachable("unhandled kind"); @@ -1523,6 +1554,9 @@ public: ComputedPropertyId getComputedPropertyId() const { switch (getKind()) { case Kind::StoredProperty: + case Kind::OptionalChain: + case Kind::OptionalForce: + case Kind::OptionalWrap: llvm_unreachable("not a computed property"); case Kind::GettableProperty: case Kind::SettableProperty: @@ -1534,6 +1568,9 @@ public: SILFunction *getComputedPropertyGetter() const { switch (getKind()) { case Kind::StoredProperty: + case Kind::OptionalChain: + case Kind::OptionalForce: + case Kind::OptionalWrap: llvm_unreachable("not a computed property"); case Kind::GettableProperty: case Kind::SettableProperty: @@ -1546,6 +1583,9 @@ public: switch (getKind()) { case Kind::StoredProperty: case Kind::GettableProperty: + case Kind::OptionalChain: + case Kind::OptionalForce: + case Kind::OptionalWrap: llvm_unreachable("not a settable computed property"); case Kind::SettableProperty: return SetterAndIdKind.getPointer(); @@ -1556,6 +1596,9 @@ public: ArrayRef getComputedPropertyIndices() const { switch (getKind()) { case Kind::StoredProperty: + case Kind::OptionalChain: + case Kind::OptionalForce: + case Kind::OptionalWrap: llvm_unreachable("not a computed property"); case Kind::GettableProperty: case Kind::SettableProperty: @@ -1589,6 +1632,24 @@ public: getter, setter, indices, ty); } + static KeyPathPatternComponent + forOptional(Kind kind, CanType ty) { + switch (kind) { + case Kind::OptionalChain: + case Kind::OptionalForce: + break; + case Kind::OptionalWrap: + assert(ty->getAnyOptionalObjectType() + && "optional wrap didn't form optional?!"); + break; + case Kind::StoredProperty: + case Kind::GettableProperty: + case Kind::SettableProperty: + llvm_unreachable("not an optional kind"); + } + return KeyPathPatternComponent(kind, ty); + } + void incrementRefCounts() const; void decrementRefCounts() const; @@ -6371,6 +6432,12 @@ public: FOREACH_IMPL_RETURN(getNumCallArguments()); } + unsigned getOperandIndexOfFirstArgument() { + FOREACH_IMPL_RETURN(getOperandIndexOfFirstArgument()); + } + +#undef FOREACH_IMPL_RETURN + /// The arguments passed to this instruction, without self. OperandValueArrayRef getArgumentsWithoutSelf() const { switch (Inst->getKind()) { @@ -6394,12 +6461,26 @@ public: case ValueKind::TryApplyInst: return 0; case ValueKind::PartialApplyInst: + // The arguments to partial_apply are a suffix of the arguments to the + // the actually-called function. return getSubstCalleeConv().getNumSILArguments() - getNumArguments(); default: llvm_unreachable("not implemented for this instruction!"); } } + // Translate the index of the argument to the full apply or partial_apply into + // to the corresponding index into the arguments of the called function. + unsigned getCalleeArgIndex(Operand &oper) { + assert(oper.getUser() == Inst); + assert(oper.getOperandNumber() >= getOperandIndexOfFirstArgument()); + + unsigned appliedArgIdx = + oper.getOperandNumber() - getOperandIndexOfFirstArgument(); + + return getCalleeArgIndexOfFirstAppliedArg() + appliedArgIdx; + } + Operand &getArgumentRef(unsigned i) const { return getArgumentOperands()[i]; } /// Return the ith argument passed to this instruction. @@ -6446,8 +6527,6 @@ public: } } -#undef FOREACH_IMPL_RETURN - SILArgumentConvention getArgumentConvention(unsigned index) const { return getSubstCalleeConv().getSILArgumentConvention(index); } diff --git a/include/swift/SIL/SILLinkage.h b/include/swift/SIL/SILLinkage.h index e83bd4ffc30..ad22db0e497 100644 --- a/include/swift/SIL/SILLinkage.h +++ b/include/swift/SIL/SILLinkage.h @@ -252,6 +252,20 @@ inline SILLinkage effectiveLinkageForClassMember(SILLinkage linkage, return linkage; } +// FIXME: This should not be necessary, but it looks like visibility rules for +// extension members are slightly bogus, and so some protocol witness thunks +// need to be public. +// +// We allow a 'public' member of an extension to witness a public +// protocol requirement, even if the extended type is not public; +// then SILGen gives the member private linkage, ignoring the more +// visible accessibility it was given in the AST. +inline bool +fixmeWitnessHasLinkageThatNeedsToBePublic(SILLinkage witnessLinkage) { + return !hasPublicVisibility(witnessLinkage) && + !hasSharedVisibility(witnessLinkage); +} + } // end swift namespace #endif diff --git a/include/swift/SIL/SILModule.h b/include/swift/SIL/SILModule.h index 638f599e28f..7fc571d46cd 100644 --- a/include/swift/SIL/SILModule.h +++ b/include/swift/SIL/SILModule.h @@ -209,9 +209,6 @@ private: /// optimizations can assume that they see the whole module. bool wholeModule; - /// True if this SILModule is being completely serialized. - bool WholeModuleSerialized; - /// The options passed into this SILModule. SILOptions &Options; @@ -222,7 +219,7 @@ private: // Intentionally marked private so that we need to use 'constructSIL()' // to construct a SILModule. SILModule(ModuleDecl *M, SILOptions &Options, const DeclContext *associatedDC, - bool wholeModule, bool wholeModuleSerialized); + bool wholeModule); SILModule(const SILModule&) = delete; void operator=(const SILModule&) = delete; @@ -285,23 +282,18 @@ public: /// /// If a source file is provided, SIL will only be emitted for decls in that /// source file, starting from the specified element number. - /// - /// If \p makeModuleFragile is true, all functions and global variables of - /// the module are marked as serialized. This is used for compiling the stdlib. static std::unique_ptr constructSIL(ModuleDecl *M, SILOptions &Options, FileUnit *sf = nullptr, Optional startElem = None, - bool makeModuleFragile = false, bool isWholeModule = false); /// \brief Create and return an empty SIL module that we can /// later parse SIL bodies directly into, without converting from an AST. static std::unique_ptr createEmptyModule(ModuleDecl *M, SILOptions &Options, - bool WholeModule = false, - bool WholeModuleSerialized = false) { + bool WholeModule = false) { return std::unique_ptr( - new SILModule(M, Options, M, WholeModule, WholeModuleSerialized)); + new SILModule(M, Options, M, WholeModule)); } /// Get the Swift module associated with this SIL module. @@ -330,7 +322,7 @@ public: } /// Returns true if everything in this SILModule is being serialized. - bool isWholeModuleSerialized() const { return WholeModuleSerialized; } + bool isWholeModuleSerialized() const { return Options.SILSerializeAll; } SILOptions &getOptions() const { return Options; } diff --git a/include/swift/SIL/SILWitnessTable.h b/include/swift/SIL/SILWitnessTable.h index 40f62c36e6a..3c6b5a119c2 100644 --- a/include/swift/SIL/SILWitnessTable.h +++ b/include/swift/SIL/SILWitnessTable.h @@ -34,8 +34,10 @@ namespace swift { class SILFunction; class SILModule; +class ProtocolConformance; class NormalProtocolConformance; enum IsSerialized_t : unsigned char; +enum class ResilienceStrategy : unsigned; /// A mapping from each requirement of a protocol to the SIL-level entity /// satisfying the requirement for a concrete type. @@ -269,13 +271,18 @@ public: void convertToDefinition(ArrayRef newEntries, IsSerialized_t isSerialized); + // Whether a conformance should be serialized. + static bool conformanceIsSerialized(ProtocolConformance *conformance, + ResilienceStrategy strategy, + bool silSerializeWitnessTables); + /// Print the witness table. void print(llvm::raw_ostream &OS, bool Verbose = false) const; /// Dump the witness table to stderr. void dump() const; }; - + } // end swift namespace //===----------------------------------------------------------------------===// diff --git a/include/swift/SILOptimizer/Analysis/AccessSummaryAnalysis.h b/include/swift/SILOptimizer/Analysis/AccessSummaryAnalysis.h index 353e079b717..6abe8fed71c 100644 --- a/include/swift/SILOptimizer/Analysis/AccessSummaryAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/AccessSummaryAnalysis.h @@ -22,6 +22,7 @@ #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" #include "swift/SILOptimizer/Analysis/BottomUpIPAnalysis.h" +#include "swift/SILOptimizer/Utils/IndexTrie.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" @@ -129,12 +130,27 @@ private: llvm::DenseMap FunctionInfos; llvm::SpecificBumpPtrAllocator Allocator; + + /// A trie of integer indices that gives pointer identity to a path of + /// projections. This is shared between all functions in the module. + IndexTrieNode *SubPathTrie; + public: - AccessSummaryAnalysis() : BottomUpIPAnalysis(AnalysisKind::AccessSummary) {} + AccessSummaryAnalysis() : BottomUpIPAnalysis(AnalysisKind::AccessSummary) { + SubPathTrie = new IndexTrieNode(); + } + + ~AccessSummaryAnalysis() { + delete SubPathTrie; + } /// Returns a summary of the accesses performed by the given function. const FunctionSummary &getOrCreateSummary(SILFunction *Fn); + IndexTrieNode *getSubPathTrieRoot() { + return SubPathTrie; + } + virtual void initialize(SILPassManager *PM) override {} virtual void invalidate() override; virtual void invalidate(SILFunction *F, InvalidationKind K) override; diff --git a/include/swift/SILOptimizer/Analysis/Analysis.def b/include/swift/SILOptimizer/Analysis/Analysis.def index 006a59b89e0..0dd8d468feb 100644 --- a/include/swift/SILOptimizer/Analysis/Analysis.def +++ b/include/swift/SILOptimizer/Analysis/Analysis.def @@ -28,6 +28,7 @@ ANALYSIS(Alias) ANALYSIS(BasicCallee) ANALYSIS(Caller) ANALYSIS(ClassHierarchy) +ANALYSIS(ClosureScope) ANALYSIS(Destructor) ANALYSIS(Dominance) ANALYSIS(EpilogueARC) diff --git a/include/swift/SILOptimizer/Analysis/ClosureScope.h b/include/swift/SILOptimizer/Analysis/ClosureScope.h new file mode 100644 index 00000000000..139c79dc7fc --- /dev/null +++ b/include/swift/SILOptimizer/Analysis/ClosureScope.h @@ -0,0 +1,185 @@ +//===--- ClosureScope.h - Determines closure's defining scope ---*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +/// +/// Map each non-escaping closure SILFunction to a set of SILFunctions +/// corresponding to its parent scopes. +/// +/// This is a lightweight analysis specific to non-escaping closures. Unlike +/// CallerAnalysis, this does not reflect the call tree. A closure's scope is a +/// function that directly references the closure. It may directly invoke the +/// closure (as a caller) or may simply pass it off as an argument. +/// +/// Like CallerAnalysis, ClosureScope is top-down, but unlike CallerAnalysis, it +/// does not require complex invalidation and recomputation. The underlying +/// assumption is that no trasformation will add new references to existing +/// non-escaping closures, with some exceptions like SILCloner. +/// +/// TODO: When this analysis is used across passes, fix SILCloner to update or +/// invalidate. In SILVerifier, if this analysis is marked valid, check that no +/// new unseen closure references have been added. +/// +/// We do not currently mark SILFunctions as non-escaping. However, only +/// closures that are not assigned to an lvalue and are never passed as escaping +/// closures can use the @inout_aliasable convention. For now, we simply limit +/// this analysis to such closures. This covers the set of closures that +/// SILOptimizer must view as non-escaping, which must in turn be a subset of +/// Sema's non-escaping closures. +/// +/// NOTE: a non-escaping function can be passed as an escaping function via +/// withoutActuallyEscaping. However, using that API to introduce recursion is +/// disallowed according to exclusivity semantics. That is, non-escaping +/// function types cannot be reentrant (SE-0176). In this analysis, we assert +/// that closure scopes are acyclic. Although the language does not currently +/// enforce non-reentrant, non-escaping closures, the scope graph cannot be +/// cyclic because there's no way to name a non-escaping closure. So, in the +/// long term the acyclic assumption made by this analysis is protected by +/// non-reentrant semantics, and in the short-term it's safe because of the +/// lanuguage's practical limitations. +/// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SILOPTIMIZER_ANALYSIS_CLOSURESCOPE_H +#define SWIFT_SILOPTIMIZER_ANALYSIS_CLOSURESCOPE_H + +#include "swift/Basic/BlotSetVector.h" +#include "swift/SIL/SILFunction.h" +#include "swift/SILOptimizer/Analysis/Analysis.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/iterator.h" + +namespace swift { + +/// Return true if this function is known to be non-escaping. +/// +/// This must only return true if the closure was also deemed non-escaping in +/// Sema. Sema will eventually guarantee non-reentrance. +/// +/// This must always return true for any closure with @inout_aliasable parameter +/// conventions, because passes like AccessEnforcementSelection assume that +/// convention only applies to non-escaping closures. +/// +/// (Hence, SILGen may only use @inout_aliasable for closures that Sema deems +/// non-escaping.) +/// +/// This may conservatively return false for any non-escaping closures that +/// don't happen to use @inout_aliasable. +inline bool isNonEscapingClosure(CanSILFunctionType funcTy) { + auto isInoutAliasable = [](SILParameterInfo paramInfo) { + return paramInfo.getConvention() + == ParameterConvention::Indirect_InoutAliasable; + }; + return llvm::any_of(funcTy->getParameters(), isInoutAliasable); +} + +class ClosureScopeData; + +class ClosureScopeAnalysis : public SILAnalysis { + friend class ClosureScopeData; + + // Get a closure's scope function from its index. This functor is compatible + // with OptionalTransformRange. Unfortunately it exposes the internals of the + // analysis data. + struct IndexLookupFunc { + // A reference to all closure parent scopes ordered by their index. + const std::vector &indexedScopes; + + IndexLookupFunc(const std::vector &indexedScopes) + : indexedScopes(indexedScopes) {} + + Optional operator()(int idx) const { + if (auto funcPtr = indexedScopes[idx]) { + return funcPtr; + } + return None; + } + }; + using IndexRange = IteratorRange; + +public: + // A range of SILFunction scopes converted from their scope indices and + // filtered to remove any erased functions. + using ScopeRange = OptionalTransformRange; + +private: + SILModule *M; + + // The analysis data. nullptr if it has never been computed. + std::unique_ptr scopeData; + +public: + ClosureScopeAnalysis(SILModule *M); + ~ClosureScopeAnalysis(); + + static bool classof(const SILAnalysis *S) { + return S->getKind() == AnalysisKind::ClosureScope; + } + + SILModule *getModule() const { return M; } + + // Return true if the given function is the parent scope for any closures. + bool isClosureScope(SILFunction *scopeFunc); + + // Return a range of scopes for the given closure. The elements of the + // returned range have type `SILFunction *` and are non-null. Returns an + // empty range for a SILFunction that is not a closure or is a dead closure. + ScopeRange getClosureScopes(SILFunction *closureFunc); + + /// Invalidate all information in this analysis. + virtual void invalidate() override; + + /// Invalidate all of the information for a specific function. + virtual void invalidate(SILFunction *F, InvalidationKind K) override { + // No invalidation needed because the analysis does not cache anything + // per call-site in functions, and we assume that references to closures + // cannot be added to functions, aside from cloning. + } + + /// Notify the analysis about a newly created function. + virtual void notifyAddFunction(SILFunction *F) override { + // Nothing to be done because the analysis does not cache anything + // per call-site in functions. + } + + /// Notify the analysis about a function which will be deleted from the + /// module. + virtual void notifyDeleteFunction(SILFunction *F) override; + + /// Notify the analysis about changed witness or vtables. + virtual void invalidateFunctionTables() override { + // witness tables have no effect on closure scopes. + } + +protected: + ClosureScopeData *getOrComputeScopeData(); +}; + +// ClosureScopeAnalysis utility for visiting functions top down in closure scope +// order. +class TopDownClosureFunctionOrder { + ClosureScopeAnalysis *CSA; + + llvm::SmallSet visited; + + BlotSetVector closureWorklist; + +public: + TopDownClosureFunctionOrder(ClosureScopeAnalysis *CSA) : CSA(CSA) {} + + // Visit all functions in a module, visiting each closure scope function + // before + // the closure function itself. + void visitFunctions(std::function visitor); +}; + +} // end namespace swift + +#endif diff --git a/include/swift/SILOptimizer/Utils/IndexTrie.h b/include/swift/SILOptimizer/Utils/IndexTrie.h index 0e62eb36a22..b7986cb4d2e 100644 --- a/include/swift/SILOptimizer/Utils/IndexTrie.h +++ b/include/swift/SILOptimizer/Utils/IndexTrie.h @@ -24,11 +24,12 @@ class IndexTrieNode { static const unsigned RootIdx = ~0U; unsigned Index; llvm::SmallVector Children; + IndexTrieNode *Parent; public: - IndexTrieNode(): Index(RootIdx) {} + IndexTrieNode(): Index(RootIdx), Parent(nullptr) {} - explicit IndexTrieNode(unsigned V): Index(V) {} + explicit IndexTrieNode(unsigned V, IndexTrieNode *P): Index(V), Parent(P) {} IndexTrieNode(IndexTrieNode &) =delete; IndexTrieNode &operator=(const IndexTrieNode&) =delete; @@ -53,12 +54,29 @@ public: }); if (I != Children.end() && (*I)->Index == Idx) return *I; - auto *N = new IndexTrieNode(Idx); + auto *N = new IndexTrieNode(Idx, this); Children.insert(I, N); return N; } ArrayRef getChildren() const { return Children; } + + IndexTrieNode *getParent() const { return Parent; } + + /// Returns true when the sequence of indices represented by this + /// node is a prefix of the sequence represented by the passed-in node. + bool isPrefixOf(const IndexTrieNode *Other) const { + const IndexTrieNode *I = Other; + + do { + if (this == I) + return true; + + I = I->getParent(); + } while (I); + + return false; + } }; } // end namespace swift diff --git a/include/swift/Sema/Semantics.h b/include/swift/Sema/Semantics.h index a2c3653d074..5c470716b8b 100644 --- a/include/swift/Sema/Semantics.h +++ b/include/swift/Sema/Semantics.h @@ -18,7 +18,7 @@ #define SWIFT_SEMA_SEMANTICMODEL_H #include "swift/AST/ASTNode.h" -#include "swift/Syntax/SyntaxData.h" +#include "swift/Syntax/Syntax.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h index a876a2b7dad..a90a8d28247 100644 --- a/include/swift/Serialization/ModuleFormat.h +++ b/include/swift/Serialization/ModuleFormat.h @@ -54,7 +54,7 @@ const uint16_t VERSION_MAJOR = 0; /// in source control, you should also update the comment to briefly /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. -const uint16_t VERSION_MINOR = 346; // Last change: dependency types for enums +const uint16_t VERSION_MINOR = 347; // Last change: 'inout' on parameter types using DeclID = PointerEmbeddedInt; using DeclIDField = BCFixed<31>; @@ -598,7 +598,8 @@ namespace decls_block { TypeIDField, // inner type BCFixed<1>, // vararg? BCFixed<1>, // autoclosure? - BCFixed<1> // escaping? + BCFixed<1>, // escaping? + BCFixed<1> // inout? >; using TupleTypeLayout = BCRecordLayout< @@ -611,7 +612,8 @@ namespace decls_block { TypeIDField, // type BCFixed<1>, // vararg? BCFixed<1>, // autoclosure? - BCFixed<1> // escaping? + BCFixed<1>, // escaping? + BCFixed<1> // inout? >; using FunctionTypeLayout = BCRecordLayout< diff --git a/include/swift/Subsystems.h b/include/swift/Subsystems.h index 05582d62c54..891fa61fc2e 100644 --- a/include/swift/Subsystems.h +++ b/include/swift/Subsystems.h @@ -132,9 +132,9 @@ namespace swift { bool TokenizeInterpolatedString = true, ArrayRef SplitTokens = ArrayRef()); - /// \brief Lex and return a vector of `RC` tokens, which include + /// \brief Lex and return a vector of `TokenSyntax` tokens, which include /// leading and trailing trivia. - std::vector, + std::vector, syntax::AbsolutePosition>> tokenizeWithTrivia(const LangOptions &LangOpts, const SourceManager &SM, @@ -192,7 +192,8 @@ namespace swift { OptionSet Options, unsigned StartElem = 0, unsigned WarnLongFunctionBodies = 0, - unsigned WarnLongExpressionTypeChecking = 0); + unsigned WarnLongExpressionTypeChecking = 0, + unsigned ExpressionTimeoutThreshold = 0); /// Once type checking is complete, this walks protocol requirements /// to resolve default witnesses. @@ -242,25 +243,19 @@ namespace swift { /// /// The module must contain source files. /// - /// If \p makeModuleFragile is true, all functions and global variables of - /// the module are marked as fragile. This is used for compiling the stdlib. /// if \p wholeModuleCompilation is true, the optimizer assumes that the SIL /// of all files in the module is present in the SILModule. std::unique_ptr performSILGeneration(ModuleDecl *M, SILOptions &options, - bool makeModuleFragile = false, bool wholeModuleCompilation = false); /// Turn a source file into SIL IR. /// /// If \p StartElem is provided, the module is assumed to be only part of the /// SourceFile, and any optimizations should take that into account. - /// If \p makeModuleFragile is true, all functions and global variables of - /// the module are marked as fragile. This is used for compiling the stdlib. std::unique_ptr performSILGeneration(FileUnit &SF, SILOptions &options, - Optional StartElem = None, - bool makeModuleFragile = false); + Optional StartElem = None); using ModuleOrSourceFile = PointerUnion; diff --git a/include/swift/Syntax/AtomicCache.h b/include/swift/Syntax/AtomicCache.h new file mode 100644 index 00000000000..1d4802e025a --- /dev/null +++ b/include/swift/Syntax/AtomicCache.h @@ -0,0 +1,74 @@ +//===------------- AtomicCache.h - Lazy Atomic Cache ------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SYNTAX_ATOMICCACHE_H +#define SWIFT_SYNTAX_ATOMICCACHE_H + +#include +#include "swift/Syntax/References.h" + +namespace swift { + +/// AtomicCache is an atomic cache for a reference-counted value. It maintains +/// a reference-counted pointer with a facility for atomically getting or +/// creating it with a lambda. +template +class AtomicCache { + // Whatever type is created through this cache must be pointer-sized, + // othwerise, we can't pretend it's a uintptr_t and use its + // compare_exchange_strong. + static_assert(sizeof(uintptr_t) == sizeof(RC), + "RC must be pointer sized!"); +private: + /// This must only be mutated in one place: AtomicCache::getOrCreate. + mutable RC Storage = nullptr; + +public: + /// The empty constructor initializes the storage to nullptr. + AtomicCache() {} + + /// Gets the value inside the cache, or creates it atomically using the + /// provided lambda if it doesn't already exist. + RC getOrCreate(std::function ()> Create) const { + auto &Ptr = *reinterpret_cast *>(&Storage); + + // If an atomic load gets an initialized value, then return Storage. + if (Ptr) { + return Storage; + } + + // We expect the uncached value to wrap a nullptr. If another thread + // beats us to caching the child, it'll be non-null, so we would + // leave it alone. + uintptr_t Expected = 0; + + // Make a RC at RefCount == 1, which we'll try to + // atomically swap in. + auto Data = Create(); + + // Try to swap in raw pointer value. + // If we won, then leave the RefCount == 1. + if (Ptr.compare_exchange_strong(Expected, + reinterpret_cast(Data.get()))) { + Data.resetWithoutRelease(); + } + + // Otherwise, the Data we just made is unfortunately useless. + // Let it die on this scope exit after its terminal release. + + return Storage; + } +}; + +} // end namespace swift + +#endif /* SWIFT_SYNTAX_ATOMICCACHE_H */ diff --git a/include/swift/Syntax/DeclSyntax.h b/include/swift/Syntax/DeclSyntax.h index 671d7371280..af263bb1d3a 100644 --- a/include/swift/Syntax/DeclSyntax.h +++ b/include/swift/Syntax/DeclSyntax.h @@ -33,40 +33,8 @@ namespace swift { namespace syntax { class ExprSyntax; -class ExprSyntaxData; class CodeBlockStmtSyntax; -class CodeBlockStmtSyntaxData; -class TypeAttributesSyntax; -class TypeAttributesSyntaxData; -class DeclModifierListSyntax; class GenericWhereClauseSyntax; -class GenericWhereClauseSyntaxData; -class GenericParameterListSyntax; -class GenericParameterListSyntaxData; - -#pragma mark declaration-modifier Data - -class DeclModifierSyntaxData final : public SyntaxData { - friend struct SyntaxFactory; - friend class SyntaxData; - friend class Syntax; - friend class DeclModifierSyntax; - - DeclModifierSyntaxData(const RC Raw, - const SyntaxData *Parent = nullptr, - const CursorIndex IndexInParent = 0); - - static RC make(const RC Raw, - const SyntaxData *Parent = nullptr, - const CursorIndex IndexInParent = 0); - - static RC makeBlank(); - -public: - static bool classof(const SyntaxData *SD) { - return SD->getKind() == SyntaxKind::DeclModifier; - } -}; #pragma mark declaration-modifier API @@ -98,7 +66,6 @@ class DeclModifierSyntax final : public Syntax { friend struct SyntaxFactory; friend class Syntax; friend class SyntaxData; - friend class DeclModifierSyntaxData; enum class Cursor : CursorIndex { Name, @@ -107,164 +74,97 @@ class DeclModifierSyntax final : public Syntax { RightParen }; - DeclModifierSyntax(const RC Root, const DataType *Data) - : Syntax(Root, Data) {} + virtual void validate() const override; public: - using DataType = DeclModifierSyntaxData; + static DeclModifierSyntax makeBlank(); + DeclModifierSyntax(const RC Root, const SyntaxData *Data) + : Syntax(Root, Data) {} /// Return the name of the modifier. - RC getName() const; + TokenSyntax getName() const; /// Return a DeclModifierSyntax with the given name. - DeclModifierSyntax withName(RC NewName) const; + DeclModifierSyntax withName(TokenSyntax NewName) const; /// Return the left parenthesis '(' token as a part of the argument clause, /// if there is one. - RC getLeftParenToken() const; + TokenSyntax getLeftParenToken() const; /// Return a DeclModifierSyntax with the given left parenthesis '(' token. - DeclModifierSyntax withLeftParenToken(RC NewLeftParen) const; + DeclModifierSyntax withLeftParenToken(TokenSyntax NewLeftParen) const; /// Get the argument to the declaration modifier. /// /// This is either: /// - 'set' for the access modifiers such as 'private' or 'public', or /// - 'safe' / 'unsafe' for the 'unowned' modifier. - RC getArgument() const; + TokenSyntax getArgument() const; /// Return a DeclModifierSyntax with the given argument. - DeclModifierSyntax withArgument(RC NewArgument) const; + DeclModifierSyntax withArgument(TokenSyntax NewArgument) const; /// Return the right parenthesis ')' token as a part of the argument clause, /// if there is one. - RC getRightParenToken() const; + TokenSyntax getRightParenToken() const; /// Return a DeclModifierSyntax with the given right parenthesis ')' token. - DeclModifierSyntax withRightParenToken(RC NewRightParen) const; + DeclModifierSyntax withRightParenToken(TokenSyntax NewRightParen) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::DeclModifier; } }; -#pragma mark declaration-modifiers Data - -using DeclModifierListSyntaxData = - SyntaxCollectionData; - -#pragma mark declaration-modifiers API - -class DeclModifierListSyntax final : - public SyntaxCollection { - - friend struct SyntaxFactory; - friend class Syntax; - friend class SyntaxData; - friend class FunctionDeclSyntax; - - using DataType = DeclModifierListSyntaxData; - - DeclModifierListSyntax(const RC Root, const DataType *Data) - : SyntaxCollection(Root, Data) {} - -public: - static bool classof(const Syntax *S) { - return S->getKind() == SyntaxKind::DeclModifierList; - } -}; - -#pragma mark declaration Data - -class DeclSyntaxData : public SyntaxData { -protected: - DeclSyntaxData(RC Raw, const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - -public: - static bool classof(const SyntaxData *S) { return S->isDecl(); } -}; - #pragma mark declaration API class DeclSyntax : public Syntax { friend class Syntax; - using DataType = DeclSyntaxData; protected: - DeclSyntax(const RC Root, const DeclSyntaxData *Data); + virtual void validate() const override {} public: + static DeclSyntax makeBlank(); + DeclSyntax(const RC Root, const SyntaxData *Data) + : Syntax(Root, Data) {} + static bool classof(const SyntaxData *S) { return S->isDecl(); } }; -#pragma mark - unknown-declaration Data - -class UnknownDeclSyntaxData : public UnknownSyntaxData { - UnknownDeclSyntaxData(RC Raw, const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); -public: - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::UnknownDecl; - } -}; - #pragma mark - unknown-declaration API class UnknownDeclSyntax : public UnknownSyntax { friend class SyntaxData; - friend class UnknownStmtSyntaxData; friend class LegacyASTTransformer; - using DataType = UnknownDeclSyntaxData; - - UnknownDeclSyntax(const RC Root, - const UnknownDeclSyntaxData *Data); + virtual void validate() const override; public: + static UnknownDeclSyntax makeBlank(); + UnknownDeclSyntax(const RC Root, const SyntaxData *Data) + : UnknownSyntax(Root, Data) {} + static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::UnknownDecl; } }; -#pragma mark declaration-members Data - -class DeclMembersSyntaxData final : public SyntaxData { - friend class SyntaxData; - friend class DeclMembersSyntaxBuilder; - friend struct SyntaxFactory; - - DeclMembersSyntaxData(RC Raw, const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - -public: - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); - - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::DeclMembers; - } -}; - #pragma mark - #pragma mark declaration-members API class DeclMembersSyntax final : public Syntax { - using DataType = DeclMembersSyntaxData; friend struct SyntaxFactory; friend class SyntaxData; friend class Syntax; friend class DeclMembersSyntaxBuilder; friend class StructDeclSyntax; - DeclMembersSyntax(RC Root, - const DeclMembersSyntaxData *Data); + virtual void validate() const override {} + public: + static DeclMembersSyntax makeBlank(); + DeclMembersSyntax(RC Root, const SyntaxData *Data) + : Syntax(Root, Data) {} static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::DeclMembers; } @@ -281,31 +181,6 @@ public: }; #pragma mark - -#pragma mark struct-declaration Data - -class StructDeclSyntaxData final : public DeclSyntaxData { - friend class SyntaxData; - friend class StructDeclSyntax; - friend class StructDeclSyntaxBuilder; - friend struct SyntaxFactory; - - RC CachedWhereClause; - RC CachedGenericParams; - RC CachedMembers; - - StructDeclSyntaxData(RC Raw, const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); - -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::StructDecl; - } -}; #pragma mark - struct-declaration API @@ -318,11 +193,9 @@ public: /// struct-members -> struct-member struct-members? /// struct-member -> declaration | compiler-control-statement class StructDeclSyntax final : public DeclSyntax { - using DataType = StructDeclSyntaxData; friend struct SyntaxFactory; friend class Syntax; friend class SyntaxData; - friend class StructDeclSyntaxData; friend class StructDeclSyntaxBuilder; enum class Cursor : CursorIndex { @@ -337,24 +210,24 @@ class StructDeclSyntax final : public DeclSyntax { Last = RightBrace, }; - StructDeclSyntax(const RC Root, const StructDeclSyntaxData *Data); - - const StructDeclSyntaxData *getData() const { - return cast(Data); - } + virtual void validate() const override; public: + static StructDeclSyntax makeBlank(); + StructDeclSyntax(const RC Root, const SyntaxData *Data) + : DeclSyntax(Root, Data) {} + /// Return the 'struct' keyword attached to the declaration. - RC getStructKeyword() const; + TokenSyntax getStructKeyword() const; /// Return a StructDeclSyntax with the given 'struct' keyword. - StructDeclSyntax withStructKeyword(RC NewStructKeyword) const; + StructDeclSyntax withStructKeyword(TokenSyntax NewStructKeyword) const; /// Return the identifier of the struct. - RC getIdentifier() const; + TokenSyntax getIdentifier() const; /// Return a StructDeclSyntax with the given identifier. - StructDeclSyntax withIdentifier(RC NewIdentifier) const; + StructDeclSyntax withIdentifier(TokenSyntax NewIdentifier) const; /// Return the generic parameter clause of the struct declaration. GenericParameterClauseSyntax getGenericParameterClause() const; @@ -372,10 +245,10 @@ public: withWhereClause(GenericWhereClauseSyntax NewWhereClause) const; /// Return the left brace '{' token of the struct declaration. - RC getLeftBraceToken() const; + TokenSyntax getLeftBraceToken() const; /// Return a StructDeclSyntax with the given left brace '{' token. - StructDeclSyntax withLeftBrace(RC NewLeftBrace) const; + StructDeclSyntax withLeftBrace(TokenSyntax NewLeftBrace) const; /// Return the members' syntax of the struct. DeclMembersSyntax getMembers() const; @@ -384,10 +257,10 @@ public: StructDeclSyntax withMembers(DeclMembersSyntax NewMembers) const; /// Return the right brace '}' token of the struct declaration. - RC getRightBraceToken() const; + TokenSyntax getRightBraceToken() const; /// Return a StructDeclSyntax with the given right brace '}' token. - StructDeclSyntax withRightBrace(RC NewRightBrace) const; + StructDeclSyntax withRightBrace(TokenSyntax NewRightBrace) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::StructDecl; @@ -400,9 +273,9 @@ class StructDeclSyntaxBuilder final { RawSyntax::LayoutList StructLayout; public: StructDeclSyntaxBuilder(); - StructDeclSyntaxBuilder &useStructKeyword(RC StructKeyword); - StructDeclSyntaxBuilder &useIdentifier(RC Identifier); - StructDeclSyntaxBuilder &useLeftBrace(RC LeftBrace); + StructDeclSyntaxBuilder &useStructKeyword(TokenSyntax StructKeyword); + StructDeclSyntaxBuilder &useIdentifier(TokenSyntax Identifier); + StructDeclSyntaxBuilder &useLeftBrace(TokenSyntax LeftBrace); StructDeclSyntaxBuilder & useGenericParameterClause(GenericParameterClauseSyntax GenericParams); @@ -411,31 +284,11 @@ public: useGenericWhereClause(GenericWhereClauseSyntax GenericWhereClause); StructDeclSyntaxBuilder &useMembers(DeclMembersSyntax Members); - StructDeclSyntaxBuilder &useRightBrace(RC RightBrace); + StructDeclSyntaxBuilder &useRightBrace(TokenSyntax RightBrace); StructDeclSyntax build() const; }; #pragma mark - -#pragma mark - type-alias Data - -class TypeAliasDeclSyntaxData final : public DeclSyntaxData { - friend class SyntaxData; - friend struct SyntaxFactory; - friend class TypeAliasDeclSyntaxBuilder; - - TypeAliasDeclSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); - -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::TypeAliasDecl; - } -}; #pragma mark - #pragma mark - type-alias API @@ -443,11 +296,8 @@ public: class TypeAliasDeclSyntax final : public DeclSyntax { friend struct SyntaxFactory; friend class SyntaxData; - friend class TypeAliasDeclSyntaxData; friend class TypeAliasDeclSyntaxBuilder; - using DataType = TypeAliasDeclSyntaxData; - enum Cursor : CursorIndex { TypeAliasKeyword, Identifier, @@ -456,23 +306,27 @@ class TypeAliasDeclSyntax final : public DeclSyntax { Type }; - TypeAliasDeclSyntax(RC Root, const TypeAliasDeclSyntaxData *Data); + virtual void validate() const override {} public: + static TypeAliasDeclSyntax makeBlank(); + TypeAliasDeclSyntax(RC Root, const SyntaxData *Data) + : DeclSyntax(Root, Data) {} + /// Return the 'typealias' keyword for the declaration. - RC getTypealiasKeyword() const { - return cast(getRaw()->getChild(Cursor::TypeAliasKeyword)); + TokenSyntax getTypealiasKeyword() const { + return { Root, Data->getChild(Cursor::TypeAliasKeyword).get() }; } /// Return a TypeAliasDeclSyntax with the given 'typealias' keyword. TypeAliasDeclSyntax - withTypeAliasKeyword(RC NewTypeAliasKeyword) const; + withTypeAliasKeyword(TokenSyntax NewTypeAliasKeyword) const; /// Return the identifier for the declaration. - RC getIdentifier() const; + TokenSyntax getIdentifier() const; /// Return a TypeAliasDeclSyntax with the given identifier. - TypeAliasDeclSyntax withIdentifier(RC NewIdentifier) const; + TypeAliasDeclSyntax withIdentifier(TokenSyntax NewIdentifier) const; /// Return the generic parameter clause of the declaration. GenericParameterClauseSyntax getGenericParameterClause() const; @@ -483,11 +337,11 @@ public: const; /// Return the equal '=' token from the declaration. - RC getEqualToken() const; + TokenSyntax getEqualToken() const; /// Return a TypeAliasDeclSyntax with the given equal '=' token. TypeAliasDeclSyntax - withEqualToken(RC NewEqualToken) const; + withEqualToken(TokenSyntax NewEqualToken) const; /// Return the type syntax to which the type alias is assigned. TypeSyntax getTypeSyntax() const; @@ -508,46 +362,20 @@ public: TypeAliasDeclSyntaxBuilder(); TypeAliasDeclSyntaxBuilder & - useTypeAliasKeyword(RC TypeAliasKeyword); + useTypeAliasKeyword(TokenSyntax TypeAliasKeyword); - TypeAliasDeclSyntaxBuilder &useIdentifier(RC Identifier); + TypeAliasDeclSyntaxBuilder &useIdentifier(TokenSyntax Identifier); TypeAliasDeclSyntaxBuilder & useGenericParameterClause(GenericParameterClauseSyntax GenericParams); - TypeAliasDeclSyntaxBuilder &useEqualToken(RC EqualToken); + TypeAliasDeclSyntaxBuilder &useEqualToken(TokenSyntax EqualToken); TypeAliasDeclSyntaxBuilder &useType(TypeSyntax ReferentType); TypeAliasDeclSyntax build() const; }; -#pragma mark - function-parameter Data - -class FunctionParameterSyntaxData final : public SyntaxData { - - friend struct SyntaxFactory; - friend class Syntax; - friend class SyntaxData; - friend class FunctionParameterSyntax; - - RC CachedTypeSyntax; - RC CachedDefaultValue; - - FunctionParameterSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC - make(RC Raw, const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); - -public: - static bool classof(const SyntaxData *SD) { - return SD->getKind() == SyntaxKind::FunctionParameter; - } -}; - #pragma mark - function-parameter API /// parameter -> @@ -557,7 +385,6 @@ class FunctionParameterSyntax final : public Syntax { friend struct SyntaxFactory; friend class Syntax; friend class SyntaxData; - friend class FunctionParameterSyntaxData; enum class Cursor : CursorIndex { ExternalName, @@ -570,34 +397,36 @@ class FunctionParameterSyntax final : public Syntax { TrailingComma, }; -public: - using DataType = FunctionParameterSyntaxData; + virtual void validate() const override; - FunctionParameterSyntax(const RC Root, const DataType *Data) +public: + static FunctionParameterSyntax makeBlank(); + + FunctionParameterSyntax(const RC Root, const SyntaxData *Data) : Syntax(Root, Data) {} /// Get the external name of the parameter, if there is one. - RC getExternalName() const; + TokenSyntax getExternalName() const; /// Return a FunctionParameterSyntax with the given external name. FunctionParameterSyntax - withExternalName(RC NewExternalName) const; + withExternalName(TokenSyntax NewExternalName) const; /// Return the local name of the parameter. - RC getLocalName() const; + TokenSyntax getLocalName() const; /// Return a FunctionParameterSyntax with the given local name. FunctionParameterSyntax - withLocalName(RC NewLocalName) const; + withLocalName(TokenSyntax NewLocalName) const; /// Return the colon ':' token between the local name and type of the /// parameter. - RC getColonToken() const; + TokenSyntax getColonToken() const; /// Return a FunctionParameterSyntax with the given colon token between /// the local name and type. FunctionParameterSyntax - withColonToken(RC NewColonToken) const; + withColonToken(TokenSyntax NewColonToken) const; /// Return the syntax for the type of this parameter. llvm::Optional getTypeSyntax() const; @@ -608,11 +437,11 @@ public: /// Return the equal '=' token in between the parameter type and the default /// value, if there is one. - RC getEqualToken() const; + TokenSyntax getEqualToken() const; /// Return a FunctionParameterSyntax with the given equal '=' token in /// between the parameter type and the default value. - FunctionParameterSyntax withEqualToken(RC NewEqualToken) const; + FunctionParameterSyntax withEqualToken(TokenSyntax NewEqualToken) const; /// Return the expression for the default value of the parameter, if there /// is one. @@ -624,11 +453,11 @@ public: withDefaultValue(llvm::Optional NewDefaultValue) const; /// Return the trailing comma on the parameter, if there is one. - RC getTrailingComma() const; + TokenSyntax getTrailingComma() const; /// Return a FunctionParameterSyntax with the given trailing comma. FunctionParameterSyntax - withTrailingComma(RC NewTrailingComma) const; + withTrailingComma(TokenSyntax NewTrailingComma) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::FunctionParameter; @@ -638,50 +467,8 @@ public: #pragma mark - function-parameter-list API /// parameter-list -> parameter | parameter ',' parameter-list -class FunctionParameterListSyntax final : public - SyntaxCollection { - friend struct SyntaxFactory; - friend class Syntax; - friend class SyntaxData; - friend class FunctionSignatureSyntax; - - using DataType = FunctionParameterListSyntaxData; - - FunctionParameterListSyntax(const RC Root, - const DataType *Data) - : SyntaxCollection(Root, Data) {} - -public: - static bool classof(const Syntax *S) { - return S->getKind() == SyntaxKind::FunctionParameterList; - } -}; - -#pragma mark - function-signature Data - -class FunctionSignatureSyntaxData final : public SyntaxData { - friend struct SyntaxFactory; - friend class SyntaxData; - friend class FunctionSignatureSyntax; - - RC CachedParameterList; - RC CachedReturnTypeAttributes; - RC CachedReturnTypeSyntax; - - FunctionSignatureSyntaxData(const RC Raw, - const SyntaxData *Parent = nullptr, - const CursorIndex IndexInParent = 0); - - static RC - make(RC Raw, const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); - -public: - static bool classof(const SyntaxData *SD) { - return SD->getKind() == SyntaxKind::FunctionSignature; - } -}; +using FunctionParameterListSyntax = + SyntaxCollection; #pragma mark - function-signature API @@ -691,7 +478,6 @@ class FunctionSignatureSyntax final : public Syntax { friend struct SyntaxBuilder; friend class Syntax; friend class SyntaxData; - friend class FunctionSignatureSyntaxData; enum class Cursor : CursorIndex { LeftParen, @@ -703,19 +489,21 @@ class FunctionSignatureSyntax final : public Syntax { ReturnType, }; -public: - using DataType = FunctionSignatureSyntaxData; + virtual void validate() const override; - FunctionSignatureSyntax(const RC Root, const DataType *Data) +public: + static FunctionSignatureSyntax makeBlank(); + + FunctionSignatureSyntax(const RC Root, const SyntaxData *Data) : Syntax(Root, Data) {} /// Return the left parenthesis '(' token enclosing the parameter list. - RC getLeftParenToken() const; + TokenSyntax getLeftParenToken() const; /// Return a FunctionSignatureSyntax with the given left parenthesis '(' token /// enclosing the parameter list. FunctionSignatureSyntax - withLeftParenToken(RC NewLeftParen) const; + withLeftParenToken(TokenSyntax NewLeftParen) const; /// Return the parameter list for this signature. FunctionParameterListSyntax getParameterList() const; @@ -725,31 +513,31 @@ public: withParameterList(FunctionParameterListSyntax NewParameterList) const; /// Return the right parenthesis ')' token enclosing the parameter list. - RC getRightParenToken() const; + TokenSyntax getRightParenToken() const; /// Return a FunctionSignatureSyntax with the given right parenthesis ')' token /// enclosing the parameter list. FunctionSignatureSyntax - withRightParenToken(RC NewRightParen) const; + withRightParenToken(TokenSyntax NewRightParen) const; /// Return the 'throws' token in this signature if it exists. - RC getThrowsToken() const; + TokenSyntax getThrowsToken() const; /// Return a FunctionSignatureSyntax with the given 'throws' token. - FunctionSignatureSyntax withThrowsToken(RC NewThrowsToken) const; + FunctionSignatureSyntax withThrowsToken(TokenSyntax NewThrowsToken) const; /// Return the 'rethrows' token in this signature if it exists; - RC getRethrowsToken() const; + TokenSyntax getRethrowsToken() const; /// Return a FunctionSignatureSyntax with the given 'rethrows' token. FunctionSignatureSyntax - withRethrowsToken(RC NewRethrowsToken) const; + withRethrowsToken(TokenSyntax NewRethrowsToken) const; /// Return the arrow '->' token for the signature. - RC getArrowToken() const; + TokenSyntax getArrowToken() const; /// Return a FunctionSignatureSyntax with the given arrow token - FunctionSignatureSyntax withArrowToken(RC NewArrowToken) const; + FunctionSignatureSyntax withArrowToken(TokenSyntax NewArrowToken) const; /// Return the return type attributes for the signature. TypeAttributesSyntax getReturnTypeAttributes() const; @@ -769,42 +557,12 @@ public: } }; -#pragma mark - function-declaration Data - -class FunctionDeclSyntaxData final : public SyntaxData { - friend struct SyntaxFactory; - friend class SyntaxData; - friend class FunctionDeclSyntax; - - RC CachedAttributes; - RC CachedModifiers; - RC CachedGenericParams; - RC CachedSignature; - RC CachedGenericWhereClause; - RC CachedBody; - - FunctionDeclSyntaxData(const RC Raw, - const SyntaxData *Parent = nullptr, - const CursorIndex IndexInParent = 0); - - static RC make(const RC Raw, - const SyntaxData *Parent = nullptr, - const CursorIndex IndexInParent = 0); - static RC makeBlank(); - -public: - static bool classof(const SyntaxData *SD) { - return SD->getKind() == SyntaxKind::FunctionDecl; - } -}; - #pragma mark - function-declaration API -class FunctionDeclSyntax final : public Syntax { +class FunctionDeclSyntax final : public DeclSyntax { friend struct SyntaxFactory; friend class Syntax; friend class SyntaxData; - friend class FunctionDeclSyntaxData; enum class Cursor : CursorIndex { Attributes, @@ -817,12 +575,13 @@ class FunctionDeclSyntax final : public Syntax { Body }; - using DataType = FunctionDeclSyntaxData; - - FunctionDeclSyntax(const RC Root, const DataType *Data) - : Syntax(Root, Data) {} + virtual void validate() const override; public: + static FunctionDeclSyntax makeBlank(); + FunctionDeclSyntax(const RC Root, const SyntaxData *Data) + : DeclSyntax(Root, Data) {} + /// Get the attributes of this function declaration. TypeAttributesSyntax getAttributes() const; @@ -836,16 +595,16 @@ public: FunctionDeclSyntax withModifiers(DeclModifierListSyntax NewModifiers) const; /// Return the 'func' keyword of this function declaration. - RC getFuncKeyword() const; + TokenSyntax getFuncKeyword() const; /// Return a FunctionDeclSyntax with the given 'func' keyword. - FunctionDeclSyntax withFuncKeyword(RC NewFuncKeyword) const; + FunctionDeclSyntax withFuncKeyword(TokenSyntax NewFuncKeyword) const; /// Return the identifier of the function declaration. - RC getIdentifier() const; + TokenSyntax getIdentifier() const; /// Return a FunctionDeclSyntax with the given identifier. - FunctionDeclSyntax withIdentifier(RC NewIdentifier) const; + FunctionDeclSyntax withIdentifier(TokenSyntax NewIdentifier) const; /// Return the generic parameter clause of the function declaration, if /// there is one. Otherwise, return llvm::None. diff --git a/include/swift/Syntax/ExprSyntax.h b/include/swift/Syntax/ExprSyntax.h index 7fe0c02e249..54ad2bcf895 100644 --- a/include/swift/Syntax/ExprSyntax.h +++ b/include/swift/Syntax/ExprSyntax.h @@ -23,7 +23,6 @@ #include "swift/Syntax/Syntax.h" #include "swift/Syntax/SyntaxData.h" #include "swift/Syntax/SyntaxCollection.h" -#include "swift/Syntax/SyntaxCollectionData.h" #include "swift/Syntax/TokenSyntax.h" #include "swift/Syntax/UnknownSyntax.h" @@ -32,99 +31,49 @@ using llvm::Optional; namespace swift { namespace syntax { -class GenericArgumentClauseSyntax; -class GenericArgumentClauseSyntaxData; -class ExprSyntaxData : public SyntaxData { -protected: - ExprSyntaxData(RC Raw, const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0) - : SyntaxData(Raw, Parent, IndexInParent) { - assert(Raw->isExpr()); - } -public: - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); - static bool classof(const SyntaxData *S) { - return S->isExpr(); - } -}; +#pragma mark - function-call-argument-list API + +class FunctionCallArgumentSyntax; + +class GenericArgumentClauseSyntax; class ExprSyntax : public Syntax { friend class FunctionParameterSyntax; -public: - using DataType = ExprSyntaxData; - ExprSyntax(const RC Root, const ExprSyntaxData *Data); +protected: + virtual void validate() const override {} + +public: + static ExprSyntax makeBlank(); + ExprSyntax(const RC Root, const SyntaxData *Data) + : Syntax(Root, Data) {} static bool classof(const Syntax *S) { return S->isExpr(); } }; -#pragma mark - unknown-expression Data - -class UnknownExprSyntaxData : public UnknownSyntaxData { - UnknownExprSyntaxData(RC Raw, const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); -public: - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::UnknownExpr; - } -}; - #pragma mark - unknown-expression API class UnknownExprSyntax : public UnknownSyntax { - friend class SyntaxData; - friend class UnknownExprSyntaxData; friend class LegacyASTTransformer; - using DataType = UnknownExprSyntaxData; - + virtual void validate() const override; public: - UnknownExprSyntax(const RC Root, - const UnknownExprSyntaxData *Data); - + static UnknownExprSyntax makeBlank(); + UnknownExprSyntax(const RC Root, const SyntaxData *Data) + : UnknownSyntax(Root, Data) {} static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::UnknownExpr; } }; -#pragma mark - integer-literal-expression Data - -class IntegerLiteralExprSyntaxData : public ExprSyntaxData { - friend struct SyntaxFactory; - friend class SyntaxData; - - IntegerLiteralExprSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::IntegerLiteralExpr; - } -}; - #pragma mark - integer-literal-expression API class IntegerLiteralExprSyntax : public ExprSyntax { - using DataType = IntegerLiteralExprSyntaxData; - friend struct SyntaxFactory; - friend class SyntaxData; - friend class IntegerLiteralExprSyntaxData; - - IntegerLiteralExprSyntax(const RC Root, - const IntegerLiteralExprSyntaxData *Data); + friend struct SyntaxFactory; + + virtual void validate() const override; enum class Cursor : CursorIndex { Sign, @@ -133,47 +82,28 @@ class IntegerLiteralExprSyntax : public ExprSyntax { public: + static IntegerLiteralExprSyntax makeBlank(); + IntegerLiteralExprSyntax(const RC Root, const SyntaxData *Data) + : ExprSyntax(Root, Data) {} + /// Get the '+' or '-' associated with this integer literal expression. - RC getSign() const; + TokenSyntax getSign() const; /// Return a new IntegerLiteralExprSyntax with the given '+' or '-' sign. - IntegerLiteralExprSyntax withSign(RC NewSign) const; + IntegerLiteralExprSyntax withSign(TokenSyntax NewSign) const; /// Return the string of digits comprising the number part of the integer /// literal expression. - RC getDigits() const; + TokenSyntax getDigits() const; /// Return a new IntegerLiteralExprSyntax with the given string of digits. - IntegerLiteralExprSyntax withDigits(RC NewDigits) const; + IntegerLiteralExprSyntax withDigits(TokenSyntax NewDigits) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::IntegerLiteralExpr; } -}; -#pragma mark - symbolic-reference Data - -class SymbolicReferenceExprSyntaxData : public ExprSyntaxData { - friend class SymbolicReferenceExprSyntax; - friend class SyntaxData; - friend struct SyntaxFactory; - - RC CachedGenericArgClause; - - SymbolicReferenceExprSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - - static RC - make(RC Raw, const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - - static RC makeBlank(); - -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::SymbolicReferenceExpr; - } + virtual ~IntegerLiteralExprSyntax() {} }; #pragma mark - symbolic-reference API @@ -184,30 +114,28 @@ public: /// in the grammar. It can be just an identifier referring to some /// declaration, or it could perhaps be a constructor call to `Array`. class SymbolicReferenceExprSyntax : public ExprSyntax { - - using DataType = SymbolicReferenceExprSyntaxData; - friend struct SyntaxFactory; - friend class SyntaxData; friend class Syntax; - friend class SymbolicReferenceExprSyntaxData; enum class Cursor : CursorIndex { Identifier, GenericArgumentClause }; - SymbolicReferenceExprSyntax(const RC Root, - const DataType *Data); + virtual void validate() const override; public: + static SymbolicReferenceExprSyntax makeBlank(); + SymbolicReferenceExprSyntax(const RC Root, const SyntaxData *Data) + : ExprSyntax(Root, Data) {} + /// Get the identifier for the symbol to which this expression refers. - RC getIdentifier() const; + TokenSyntax getIdentifier() const; /// Return a new `SymbolicReferenceExprSyntax` with the given identifier. SymbolicReferenceExprSyntax - withIdentifier(RC NewIdentifier) const; + withIdentifier(TokenSyntax NewIdentifier) const; /// Return the generic arguments this symbolic reference has, if it has one. llvm::Optional getGenericArgumentClause() const; @@ -222,44 +150,13 @@ public: } }; -#pragma mark - function-call-argument Data - -class FunctionCallArgumentSyntaxData : public SyntaxData { - friend struct SyntaxFactory; - friend class FunctionCallArgumentSyntax; - friend class SyntaxData; - - RC CachedExpression; - - FunctionCallArgumentSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - - static RC - make(RC Raw, const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - - static RC makeBlank(); - -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::FunctionCallArgument; - } -}; - #pragma mark - function-call-argument API /// function-call-argument -> label? ':'? (expression | operator) ','? class FunctionCallArgumentSyntax : public Syntax { - using DataType = FunctionCallArgumentSyntaxData; friend struct SyntaxFactory; - friend class SyntaxData; friend class Syntax; - friend class FunctionCallArgumentSyntaxData; - friend class FunctionCallArgumentListSyntax; - friend class SyntaxCollectionData; friend class SyntaxCollection; @@ -270,23 +167,26 @@ class FunctionCallArgumentSyntax : public Syntax { Comma, }; - FunctionCallArgumentSyntax(const RC Root, - const DataType *Data); + virtual void validate() const override; public: + static FunctionCallArgumentSyntax makeBlank(); + FunctionCallArgumentSyntax(const RC Root, const SyntaxData *Data) + : Syntax(Root, Data) {} + /// Return the label identifier for this argument, if it has one. - RC getLabel() const; + TokenSyntax getLabel() const; /// Return a new `FunctionCallArgumentSyntax` with the given label. - FunctionCallArgumentSyntax withLabel(RC NewLabel) const; + FunctionCallArgumentSyntax withLabel(TokenSyntax NewLabel) const; /// Get the colon ':' token in between the label and argument, /// if there is one. - RC getColonToken() const; + TokenSyntax getColonToken() const; /// Return a new `FunctionCallArgumentSyntax` with the given colon ':' token. - FunctionCallArgumentSyntax withColonToken(RC NewColon) const; + FunctionCallArgumentSyntax withColonToken(TokenSyntax NewColon) const; /// Returns the expression of the argument. llvm::Optional getExpression() const; @@ -297,84 +197,25 @@ public: /// Get the comma ',' token immediately following this argument, if there /// is one. - RC getTrailingComma() const; + TokenSyntax getTrailingComma() const; /// Return a new `FunctionCallArgumentSyntax` with the given comma attached /// to the end of the argument. FunctionCallArgumentSyntax - withTrailingComma(RC NewTrailingComma) const; + withTrailingComma(TokenSyntax NewTrailingComma) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::FunctionCallArgument; } }; -#pragma mark - function-call-argument-list Data - -using FunctionCallArgumentListSyntaxData = - SyntaxCollectionData; - -#pragma mark - function-call-argument-list API - -/// function-call-argument-list -> function-call-argument -/// function-call-argument-list? -class FunctionCallArgumentListSyntax - : public SyntaxCollection { - friend struct SyntaxFactory; - friend class FunctionCallExprSyntax; - friend class Syntax; - friend class SyntaxData; - - using DataType = FunctionCallArgumentListSyntaxData; - - FunctionCallArgumentListSyntax(const RC Root, - const DataType *Data); - -public: - static bool classof(const Syntax *S) { - return S->getKind() == SyntaxKind::FunctionCallArgumentList; - } -}; - -#pragma mark - function-call-expression Data - -class FunctionCallExprSyntaxData : public ExprSyntaxData { - friend struct SyntaxFactory; - friend class FunctionCallExprSyntax; - friend class FunctionCallExprSyntaxBuilder; - friend class SyntaxData; - - RC CachedCalledExpression; - RC CachedArgumentList; - - FunctionCallExprSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - - static RC - make(RC Raw, const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - - static RC makeBlank(); - -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::FunctionCallExpr; - } -}; - #pragma mark - function-call-expression API class FunctionCallExprSyntax : public ExprSyntax { - using DataType = FunctionCallExprSyntaxData; friend struct SyntaxFactory; - friend class FunctionCallExprSyntaxData; friend class FunctionCallExprSyntaxBuilder; friend class Syntax; - friend class SyntaxData; - + enum class Cursor: CursorIndex { CalledExpression, LeftParen, @@ -382,9 +223,12 @@ class FunctionCallExprSyntax : public ExprSyntax { RightParen, }; - FunctionCallExprSyntax(const RC Root, const DataType *Data); + virtual void validate() const override; public: + static FunctionCallExprSyntax makeBlank(); + FunctionCallExprSyntax(const RC Root, const SyntaxData *Data) + : ExprSyntax(Root, Data) {} /// Get the base expression getting called. ExprSyntax getCalledExpression() const; @@ -395,11 +239,11 @@ public: withCalledExpression(ExprSyntax NewBaseExpression) const; /// Return the left parenthesis '(' token in this call. - RC getLeftParen() const; + TokenSyntax getLeftParen() const; /// Return a new `FunctionCallExprSyntax` with the given left parenthesis '(' /// token. - FunctionCallExprSyntax withLeftParen(RC NewLeftParen) const; + FunctionCallExprSyntax withLeftParen(TokenSyntax NewLeftParen) const; /// Get the list of arguments in this call expression. FunctionCallArgumentListSyntax getArgumentList() const; @@ -409,11 +253,11 @@ public: withArgumentList(FunctionCallArgumentListSyntax NewArgumentList) const; /// Return the right parenthesis ')' token in this call. - RC getRightParen() const; + TokenSyntax getRightParen() const; /// Return a new `FunctionCallExprSyntax` with the given right parenthesis ')' /// token. - FunctionCallExprSyntax withRightParen(RC NewLeftParen) const; + FunctionCallExprSyntax withRightParen(TokenSyntax NewLeftParen) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::FunctionCallExpr; @@ -434,14 +278,14 @@ public: useCalledExpression(ExprSyntax CalledExpression); /// Use the given left parenthesis '(' token in the function call. - FunctionCallExprSyntaxBuilder &useLeftParen(RC LeftParen); + FunctionCallExprSyntaxBuilder &useLeftParen(TokenSyntax LeftParen); /// Add an additional argument to the layout. FunctionCallExprSyntaxBuilder & appendArgument(FunctionCallArgumentSyntax AdditionalArgument); /// Use the given right parenthesis ')' token in the function call. - FunctionCallExprSyntaxBuilder &useRightParen(RC RightParen); + FunctionCallExprSyntaxBuilder &useRightParen(TokenSyntax RightParen); /// Return a `FunctionCallExprSyntax` with the arguments added so far. FunctionCallExprSyntax build() const; diff --git a/include/swift/Syntax/GenericSyntax.h b/include/swift/Syntax/GenericSyntax.h index d8510db3b4b..a393dedda47 100644 --- a/include/swift/Syntax/GenericSyntax.h +++ b/include/swift/Syntax/GenericSyntax.h @@ -27,71 +27,23 @@ namespace swift { namespace syntax { class TypeSyntax; -class TypeSyntaxData; class TypeIdentifierSyntax; -class TypeIdentifierSyntaxData; - -#pragma mark - generic-requirement Data - -class GenericRequirementSyntaxData : public SyntaxData { - friend class GenericRequirementSyntax; - friend class SyntaxData; - -protected: - GenericRequirementSyntaxData(const RC Raw, - const SyntaxData *Parent = nullptr, - const CursorIndex IndexInParent = 0) - : SyntaxData(Raw, Parent, IndexInParent) {} - -public: - static bool classof(const SyntaxData *SD) { - return SD->getKind() == SyntaxKind::ConformanceRequirement || - SD->getKind() == SyntaxKind::SameTypeRequirement; - } -}; #pragma mark - generic-requirement API class GenericRequirementSyntax : public Syntax { friend class Syntax; - friend class SyntaxData; - friend class GenericRequirementSyntaxData; - + +protected: + virtual void validate() const override {} public: - using DataType = GenericRequirementSyntaxData; - - GenericRequirementSyntax(const RC Root, const DataType *Data) + static GenericRequirementSyntax makeBlank(); + GenericRequirementSyntax(const RC Root, + const SyntaxData *Data) : Syntax(Root, Data) {} - static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::ConformanceRequirement || - S->getKind() == SyntaxKind::SameTypeRequirement; - } -}; - -#pragma mark - conformance-requirement Data - -class ConformanceRequirementSyntaxData final - : public GenericRequirementSyntaxData { - friend class SyntaxData; - - RC CachedConformingTypeIdentifier; - RC InheritedType; - - ConformanceRequirementSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC - make(RC Raw, const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); - -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::ConformanceRequirement; - } - static bool classof(const GenericRequirementSyntaxData *SD) { - return SD->getKind() == SyntaxKind::ConformanceRequirement; + S->getKind() == SyntaxKind::SameTypeRequirement; } }; @@ -100,8 +52,6 @@ public: /// conformance-requirement -> type-identifier : type-identifier class ConformanceRequirementSyntax final : public GenericRequirementSyntax { - friend class ConformanceRequirementSyntaxData; - friend class SyntaxData; friend class Syntax; enum Cursor : CursorIndex { @@ -110,33 +60,29 @@ class ConformanceRequirementSyntax final : public GenericRequirementSyntax { RightTypeIdentifier, }; - ConformanceRequirementSyntax(RC Root, - ConformanceRequirementSyntaxData *Data); - - static ConformanceRequirementSyntax make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - - static ConformanceRequirementSyntax makeBlank(); - +protected: + virtual void validate() const override; public: - using DataType = ConformanceRequirementSyntaxData; + static ConformanceRequirementSyntax makeBlank(); + ConformanceRequirementSyntax(const RC Root, + const SyntaxData *Data) + : GenericRequirementSyntax(Root, Data) {} - /// Return the conforming "left-hand" type identifier in the + /// Return the conforming "left-hand" type identifier in the /// conformance requirement. TypeIdentifierSyntax getConformingTypeIdentifier() const; /// Return a new ConformanceRequirementSyntax with the given conforming /// "left-hand" type identifier. ConformanceRequirementSyntax - withConformingTypeIdentifier(RC NewTypeIdentifier) const; + withConformingTypeIdentifier(TokenSyntax NewTypeIdentifier) const; /// Return the colon token in the conformance requirement. - RC getColonToken() const; + TokenSyntax getColonToken() const; /// Return a new ConformanceRequirementSyntax with the given colon token. ConformanceRequirementSyntax - withColonToken(RC NewColonToken); + withColonToken(TokenSyntax NewColonToken); /// Return the "right-hand" inherited type from the conformance requirement. TypeIdentifierSyntax getInheritedType() const; @@ -153,52 +99,27 @@ public: } }; -#pragma mark - same-type-requirement Data - -class SameTypeRequirementSyntaxData final - : public GenericRequirementSyntaxData { - friend struct SyntaxFactory; - friend class SyntaxData; - - RC CachedLeftTypeIdentifier; - RC CachedRightType; - - SameTypeRequirementSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC - make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); - -public: -static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::SameTypeRequirement; -} -}; - #pragma mark -same-type-requirement API /// same-type-requirement -> type-identifier == type class SameTypeRequirementSyntax final : public Syntax { friend struct SyntaxFactory; friend class Syntax; - friend class SyntaxData; - friend class SameTypeRequirementSyntaxData; enum Cursor : CursorIndex { LeftTypeIdentifier, EqualityToken, RightType, }; - SameTypeRequirementSyntax(RC Root, - const SameTypeRequirementSyntaxData *Data); + virtual void validate() const override; public: - using DataType = SameTypeRequirementSyntaxData; + static SameTypeRequirementSyntax makeBlank(); + SameTypeRequirementSyntax(const RC Root, + const SyntaxData *Data) + : Syntax(Root, Data) {} - /// Return the type identifier on the left side of the same-type requirement. + /// Return the type identifier on the left side of the same-type requirement. TypeIdentifierSyntax getLeftTypeIdentifier() const; /// Return a SameTypeRequirementSyntax with the given type identifier on @@ -207,10 +128,10 @@ public: withLeftTypeIdentifier(TypeIdentifierSyntax NewLeftTypeIdentifier) const; /// Return the equality '==' operator token from the same-type requirement. - RC getEqualityToken() const; + TokenSyntax getEqualityToken() const; SameTypeRequirementSyntax - withEqualityToken(RC NewEqualityToken) const; + withEqualityToken(TokenSyntax NewEqualityToken) const; /// Return the type syntax from the right side of the same-type requirement. TypeSyntax getRightType() const; @@ -224,28 +145,6 @@ public: } }; -#pragma mark generic-parameter Data - - class GenericParameterSyntaxData final : public SyntaxData { - friend class SyntaxData; - friend struct SyntaxFactory; - RC CachedInheritedType; - - GenericParameterSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - - static RC - make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); - - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::GenericParameterClause; - } - }; - #pragma mark - generic-parameter API /// generic-parameter -> type-name @@ -260,25 +159,29 @@ class GenericParameterSyntax final : public Syntax { InheritedType, }; - GenericParameterSyntax(RC Root, - const GenericParameterSyntaxData *Data); +protected: + virtual void validate() const override; public: + static GenericParameterSyntax makeBlank(); + GenericParameterSyntax(const RC Root, + const SyntaxData *Data) + : Syntax(Root, Data) {} /// Return the name of the generic parameter. - RC getIdentifier() const; + TokenSyntax getIdentifier() const; /// Returns a GenericParameterSyntax with the given parameter identifier GenericParameterSyntax - withIdentifier(RC NewIdentifier) const; + withIdentifier(TokenSyntax NewIdentifier) const; /// Return the colon token before the inherited type, if applicable. - RC getColonToken() const; + TokenSyntax getColonToken() const; /// Return a GenericParameterSyntax with the given colon token before the /// inherited type. GenericParameterSyntax - withColonToken(RC NewColonToken) const; + withColonToken(TokenSyntax NewColonToken) const; /// Return the inherited type or protocol composition to which the /// parameter conforms, if applicable. @@ -296,64 +199,11 @@ public: } }; - -#pragma mark - generic-parameter-list Data - -class GenericParameterListSyntaxData final : public SyntaxData { - friend class SyntaxData; - - GenericParameterListSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC - make(RC Raw, const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); - -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::GenericParameterList; - } -}; - -#pragma mark - generic-parameter-list API - -/// generic-parameter-list -> generic-parameter -/// | generic-parameter ',' generic-parameter-list -class GenericParameterListSyntax final : public Syntax { - friend struct SyntaxFactory; -}; - -#pragma mark generic-parameter-clause Data - -class GenericParameterClauseSyntaxData final : public SyntaxData { - friend class SyntaxData; - friend struct SyntaxFactory; - friend class GenericParameterClauseBuilder; - - RC CachedGenericParameterList; - - GenericParameterClauseSyntaxData(const RC Raw, - const SyntaxData *Parent = nullptr, - const CursorIndex IndexInParent = 0); - static RC - make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); - -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::GenericParameterClause; - } -}; - #pragma mark - generic-parameter-clause API /// generic-parameter-clause -> '<' generic-argument-list '>' class GenericParameterClauseSyntax final : public Syntax { friend struct SyntaxFactory; - friend class GenericParameterClauseSyntaxData; friend class GenericParameterClauseBuilder; friend class FunctionDeclSyntax; @@ -363,17 +213,21 @@ class GenericParameterClauseSyntax final : public Syntax { RightAngleBracketToken, }; - GenericParameterClauseSyntax(RC Root, - const GenericParameterClauseSyntaxData *Data); +protected: + virtual void validate() const override; public: + static GenericParameterClauseSyntax makeBlank(); + GenericParameterClauseSyntax(const RC Root, + const SyntaxData *Data) + : Syntax(Root, Data) {} /// Return the left angle bracket '<' token on the generic parameter clause. - RC getLeftAngleBracket() const; + TokenSyntax getLeftAngleBracket() const; /// Return a new GenericParameterClauseSyntax with the given left angle /// bracket '<' token. GenericParameterClauseSyntax - withLeftAngleBracket(RC NewLeftAngleBracketToken) const; + withLeftAngleBracket(TokenSyntax NewLeftAngleBracketToken) const; /// Return the GenericParameterListSyntax inside the angle bracket tokens. GenericParameterListSyntax getGenericParameterList() const; @@ -384,12 +238,12 @@ public: withGenericParams(GenericParameterListSyntax NewGenericParams) const; /// Return the right angle bracket '>' token on the generic parameter clause. - RC getRightAngleBracket() const; + TokenSyntax getRightAngleBracket() const; /// Return a GenericParameterClauseSyntax with the given right angle /// bracket '>' token. GenericParameterClauseSyntax - withRightAngleBracket(RC NewRightAngleBracketToken) const; + withRightAngleBracket(TokenSyntax NewRightAngleBracketToken) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::GenericParameterClause; } @@ -398,93 +252,26 @@ public: #pragma mark - generic-parameter-clause Builder class GenericParameterClauseBuilder { - RC LeftAngleToken; + RC LeftAngleToken; RawSyntax::LayoutList ParameterListLayout; - RC RightAngleToken; + RC RightAngleToken; public: GenericParameterClauseBuilder(); GenericParameterClauseBuilder & - useLeftAngleBracket(RC LeftAngleBracket); + useLeftAngleBracket(TokenSyntax LeftAngleBracket); GenericParameterClauseBuilder & - addParameter(llvm::Optional> MaybeComma, + addParameter(llvm::Optional MaybeComma, GenericParameterSyntax Parameter); GenericParameterClauseBuilder & - useRightAngleBracket(RC RightAngleBracket); + useRightAngleBracket(TokenSyntax RightAngleBracket); GenericParameterClauseSyntax build() const; }; -#pragma mark - generic-argument-list Data - -class GenericArgumentListSyntaxData final : public SyntaxData { - friend class SyntaxData; - GenericArgumentListSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC - make(RC Raw, const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::GenericArgumentList; - } -}; - -#pragma mark - generic-argument-list API - -/// generic-argument-list -> generic-argument -/// | generic-argument ',' generic-argument-list -class GenericArgumentListSyntax final : public Syntax { - friend struct SyntaxFactory; - - GenericArgumentListSyntax(RC Root, - GenericArgumentListSyntaxData *Data); - - static GenericArgumentListSyntax make(RC Raw); - - static GenericArgumentListSyntax makeBlank(); - -public: - /// Get the n-th generic argument from this list. - TypeSyntax getArgument(unsigned n) const; - - /// Return a GenericArgumentListSyntax with the given generic argument added. - GenericArgumentListSyntax - addGenericArgument(llvm::Optional> Comma, - TypeSyntax NewArgument) const; - - static bool classof (const Syntax *S) { - return S->getKind() == SyntaxKind::GenericArgumentList; - } -}; - -#pragma mark - generic-argument-clause Data - -class GenericArgumentClauseSyntaxData final : public SyntaxData { - friend class SyntaxData; - friend struct SyntaxFactory; - friend class GenericArgumentClauseBuilder; - RC CachedGenericArgumentList; - - GenericArgumentClauseSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC - make(RC Raw, const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); - -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::GenericArgumentClause; - } -}; - #pragma mark - generic-argument-clause API /// generic-argument-clause -> '<' generic-argument-list '>' @@ -492,28 +279,30 @@ class GenericArgumentClauseSyntax : public Syntax { friend struct SyntaxFactory; friend class GenericArgumentClauseBuilder; friend class SymbolicReferenceExprSyntax; - friend class SyntaxData; friend class Syntax; - using DataType = GenericArgumentClauseSyntaxData; - - enum class Cursor : CursorIndex { + enum class Cursor : CursorIndex { LeftAngleBracketToken, GenericArgumentList, RightAngleBracketToken, }; - GenericArgumentClauseSyntax(RC Root, - const GenericArgumentClauseSyntaxData *Data); +protected: + virtual void validate() const override {} public: + static GenericArgumentClauseSyntax makeBlank(); + GenericArgumentClauseSyntax(const RC Root, + const SyntaxData *Data) + : Syntax(Root, Data) {} + /// Return the left angle bracket '<' token on the generic argument clause. - RC getLeftAngleBracket() const; + TokenSyntax getLeftAngleBracket() const; /// Return a new GenericArgumentClauseSyntax with the given left angle /// bracket '<' token. GenericArgumentClauseSyntax - withLeftAngleBracket(RC NewLeftAngleBracket) const; + withLeftAngleBracket(TokenSyntax NewLeftAngleBracket) const; /// Return the GenericArgumentClauseSyntax inside the angle bracket tokens. GenericArgumentListSyntax getGenericParameterList() const; @@ -524,116 +313,65 @@ public: withGenericParams(GenericParameterListSyntax NewGenericParams) const; /// Return the right angle bracket '>' token on the generic argument clause. - RC getRightAngleBracket() const; + TokenSyntax getRightAngleBracket() const; /// Return a new GenericArgumentClauseSyntax with the given right angle /// bracket '>' token. GenericArgumentClauseSyntax - withRightAngleBracket(RC NewRightAngleBracket) const; + withRightAngleBracket(TokenSyntax NewRightAngleBracket) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::GenericArgumentClause; } }; -#pragma mark - generic-requirement-list Data - -using GenericRequirementListSyntaxData = - SyntaxCollectionData; - -#pragma mark - generic-requirement-list API - -/// requirement-list -> requirement | requirement ',' requirement-list -/// -/// requirement -> conformance-requirement | same-type-requirement -class GenericRequirementListSyntax final - : public SyntaxCollection { - friend struct SyntaxFactory; - friend class Syntax; - friend class SyntaxData; - - using DataType = GenericRequirementListSyntaxData; - - GenericRequirementListSyntax(const RC Root, - const DataType *Data) - : SyntaxCollection(Root, Data) {} -public: - static bool classof(const Syntax *S) { - return S->getKind() == SyntaxKind::GenericRequirementList; - } -}; - #pragma mark - generic-argument-clause Builder class GenericArgumentClauseBuilder { - RC LeftAngleToken; + RC LeftAngleToken; RawSyntax::LayoutList ArgumentListLayout; - RC RightAngleToken; + RC RightAngleToken; public: GenericArgumentClauseBuilder(); GenericArgumentClauseBuilder & - useLeftAngleBracket(RC LeftAngleBracket); + useLeftAngleBracket(TokenSyntax LeftAngleBracket); GenericArgumentClauseBuilder & - addGenericArgument(llvm::Optional> MaybeComma, + addGenericArgument(llvm::Optional MaybeComma, TypeSyntax ArgumentTypeSyntax); GenericArgumentClauseBuilder & - useRightAngleBracket(RC RightAngleBracket); + useRightAngleBracket(TokenSyntax RightAngleBracket); GenericArgumentClauseSyntax build() const; }; -#pragma mark - generic-where-clause Data - -class GenericWhereClauseSyntaxData final : public SyntaxData { - friend class SyntaxData; - friend struct SyntaxFactory; - - RC CachedRequirementList; - - GenericWhereClauseSyntaxData(const RC Raw, - const SyntaxData *Parent = nullptr, - const CursorIndex IndexInParent = 0); - static RC - make(const RC Raw, const SyntaxData *Parent = nullptr, - const CursorIndex IndexInParent = 0); - static RC makeBlank(); - -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::GenericWhereClause; - } -}; - #pragma mark - generic-where-clause API /// generic-where-clause -> 'where' requirement-list class GenericWhereClauseSyntax final : public Syntax { friend struct SyntaxFactory; friend class Syntax; - friend class SyntaxData; - friend class GenericWhereClauseSyntaxData; enum class Cursor : CursorIndex { WhereKeyword, RequirementList, }; - using DataType = GenericWhereClauseSyntaxData; - - GenericWhereClauseSyntax(RC Root, - const GenericWhereClauseSyntaxData *Data); +protected: + virtual void validate() const override; public: + static GenericWhereClauseSyntax makeBlank(); + GenericWhereClauseSyntax(const RC Root, const SyntaxData *Data) + : Syntax(Root, Data) {} + /// Return the 'where' keyword in the generic where clause. - RC getWhereKeyword() const; + TokenSyntax getWhereKeyword() const; /// Return a GenericWhereClauseSyntax with the given 'where' keyword. GenericWhereClauseSyntax - withWhereKeyword(RC NewWhereKeyword) const; + withWhereKeyword(TokenSyntax NewWhereKeyword) const; /// Return the requirement list from the where clause. GenericRequirementListSyntax getRequirementList() const; diff --git a/include/swift/Syntax/LegacyASTTransformer.h b/include/swift/Syntax/LegacyASTTransformer.h index d6d8ba89191..f06fceb6514 100644 --- a/include/swift/Syntax/LegacyASTTransformer.h +++ b/include/swift/Syntax/LegacyASTTransformer.h @@ -31,7 +31,7 @@ namespace swift { namespace syntax { -using TokenPositionList = std::vector, +using TokenPositionList = std::vector, AbsolutePosition>>; /// Transforms a swift/AST into a swift/Syntax/RC. @@ -93,13 +93,13 @@ public: #include "swift/AST/ExprNodes.def" }; -/// Transform a legacy AST node to a full-fidelity `RC`. +/// Transform a legacy AST node to a full-fidelity `Syntax`. /// -/// If an ASTNode's kind isn't covered by the transform, a `RC` for -/// a SyntaxKind::Unknown will be returned containing all of the TokenSyntaxs that -/// comprise the node. +/// If an ASTNode's kind isn't covered by the transform, an `UnknownSyntax` +/// will be returned containing all of the `TokenSyntax`es that comprise the +/// node. /// -/// If the node isn't expressible in a `RC`, then `None` is returned. +/// If the node isn't expressible in a `Syntax`, then `None` is returned. Optional transformAST(ASTNode Node, sema::Semantics &Sema, @@ -108,14 +108,14 @@ transformAST(ASTNode Node, const TokenPositionList &Tokens); /// Do a binary search for a token at the given `Offset`. -RC findTokenSyntax(tok ExpectedKind, +TokenSyntax findTokenSyntax(tok ExpectedKind, OwnedString ExpectedText, SourceManager &SourceMgr, SourceLoc Loc, unsigned BufferID, const TokenPositionList &Tokens); -//ArrayRef> +//ArrayRef //syntax::tokensInRange(SourceRange Range, const TokenPositionList &Tokens); } // end namespace syntax diff --git a/include/swift/Syntax/RawSyntax.h b/include/swift/Syntax/RawSyntax.h index 4bf2a3adbe0..59f3bf6524b 100644 --- a/include/swift/Syntax/RawSyntax.h +++ b/include/swift/Syntax/RawSyntax.h @@ -18,7 +18,7 @@ // They are reference-counted and strictly immutable, so can be shared freely // among Syntax nodes and have no specific identity. They could even in theory // be shared for expressions like 1 + 1 + 1 + 1 - you don't need 7 syntax nodes -// to expressSwiftTypeConverter that at this layer. +// to express that at this layer. // // These are internal implementation ONLY - do not expose anything involving // RawSyntax publicly. Clients of lib/Syntax should not be aware that they @@ -50,26 +50,29 @@ using llvm::StringRef; #ifndef NDEBUG #define syntax_assert_child_token(Raw, Cursor, TokenKind) \ - (assert(cast(Raw->getChild(Cursor))->getTokenKind() == TokenKind)); + (assert(cast(Raw->getChild(Cursor))->getTokenKind() == \ + TokenKind)); #else #define syntax_assert_child_token(Raw, Cursor, TokenKind) ((void)0); #endif #ifndef NDEBUG #define syntax_assert_child_token_text(Raw, Cursor, TokenKind, Text) \ - (assert(cast(Raw->getChild(Cursor))->getTokenKind() == \ - TokenKind)); \ - (assert(cast(Raw->getChild(Cursor))->getText() == Text)); + ({ \ + auto __Child = cast(Raw->getChild(Cursor)); \ + assert(__Child->getTokenKind() == TokenKind); \ + assert(__Child->getText() == Text); \ + }) #else #define syntax_assert_child_token_text(Raw, Cursor, TokenKind, Text) ((void)0); #endif #ifndef NDEBUG #define syntax_assert_token_is(Tok, Kind, Text) \ - { \ - assert(Tok->getTokenKind() == Kind); \ - assert(Tok->getText() == Text); \ - } + ({ \ + assert(Tok.getTokenKind() == Kind); \ + assert(Tok.getText() == Text); \ + }) #else #define syntax_assert_token_is(Tok, Kind, Text) ((void)0); #endif diff --git a/include/swift/Syntax/RawTokenSyntax.h b/include/swift/Syntax/RawTokenSyntax.h new file mode 100644 index 00000000000..e5c58dce507 --- /dev/null +++ b/include/swift/Syntax/RawTokenSyntax.h @@ -0,0 +1,203 @@ +//===------- RawTokenSyntax.h - Swift Raw Token Interface -------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file contains the interface for a `RawTokenSyntax`, which is a token +// that includes full-fidelity leading and trailing trivia. +// +// A `RawTokenSyntax` is an instance of `RawSyntax`, meaning it is immutable, +// reference counted, and able to be shared. It is an implementation detail; +// most users of tokens should use `TokenSyntax` instead. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SYNTAX_RAWTOKENSYNTAX_H +#define SWIFT_SYNTAX_RAWTOKENSYNTAX_H + +#include "swift/Syntax/RawSyntax.h" +#include "swift/Syntax/References.h" +#include "swift/Syntax/Syntax.h" +#include "swift/Syntax/TokenKinds.h" +#include "swift/Syntax/Trivia.h" + +namespace swift { +namespace syntax { + +class AbsolutePosition; + +struct RawTokenSyntax final : public RawSyntax { + friend struct SyntaxFactory; + const tok TokenKind; + const OwnedString Text; + const Trivia LeadingTrivia; + const Trivia TrailingTrivia; + +private: + RawTokenSyntax(); + + RawTokenSyntax(tok TokenKind, OwnedString Text, + const SourcePresence Presence); + + RawTokenSyntax(tok TokenKind, OwnedString Text, const SourcePresence Presence, + const Trivia &LeadingTrivia, const Trivia &TrailingTrivia); + +public: + /// Make a new token. + static RC make(tok TokenKind, OwnedString Text, + const SourcePresence Presence, + const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia) { + return RC { + new RawTokenSyntax { + TokenKind, Text, Presence, + LeadingTrivia, TrailingTrivia + } + }; + } + + /// Return a token with the specified kind and text, but marked as missing. + static RC missingToken(const tok Kind, OwnedString Text) { + return make(Kind, Text, SourcePresence::Missing, {}, {}); + } + + /// Return a new token like this one, but with the given leading + /// trivia instead. + RC withLeadingTrivia(const Trivia &NewLeadingTrivia) const { + return make(TokenKind, Text, Presence, NewLeadingTrivia, TrailingTrivia); + } + + /// Return a new token like this one, but with the given trailing + /// trivia instead. + RC withTrailingTrivia(const Trivia &NewTrailingTrivia) const { + return make(TokenKind, Text, Presence, LeadingTrivia, NewTrailingTrivia); + } + + /// Returns true if the token is of the expected kind and has the given + /// expected text. + bool is(tok ExpectedKind, StringRef ExpectedText) const { + return getTokenKind() == ExpectedKind && ExpectedText == getText(); + } + + /// Returns the kind of token this is. + tok getTokenKind() const { return TokenKind; } + + /// Returns a reference to the text of this token. + StringRef getText() const { return Text.str(); } + + /// True if the token is any keyword. + bool isKeyword() const { + switch (TokenKind) { +#define KEYWORD(X) case tok::kw_##X: return true; +#include "swift/Syntax/TokenKinds.def" + default: return false; + } + } + + /// Returns true if the token is any literal. + bool isLiteral() const { + switch(TokenKind) { + case tok::integer_literal: + case tok::floating_literal: + case tok::string_literal: + case tok::pound_fileLiteral: + case tok::pound_colorLiteral: + case tok::pound_imageLiteral: + return true; + default: + return false; + } + } + + /// Returns true if this token is of the specified kind. + bool is(tok K) const { return TokenKind == K; } + + /// Returns true if this token is not of the specified kind. + bool isNot(tok K) const { return TokenKind != K; } + + /// Base case for variadic `isAny` + bool isAny(tok K1) const { + return is(K1); + } + + /// Returns true if this token is any of the provided kinds. + template + bool isAny(tok K1, tok K2, T... K) const { + if (is(K1)) + return true; + return isAny(K2, K...); + } + + /// Returns true if this token is not any of the provided kinds. + template + bool isNot(tok K1, T... K) const { return !isAny(K1, K...); } + + bool isPunctuation() const { + switch (TokenKind) { +#define PUNCTUATOR(Name, Str) case tok::Name: return true; +#include "swift/Syntax/TokenKinds.def" + default: return false; + } + } + + /// Returns true if this token is a binary operator. + bool isBinaryOperator() const { + return TokenKind == tok::oper_binary_spaced || + TokenKind == tok::oper_binary_unspaced; + } + + /// Returns true if this token is any kind of operator. + bool isOperator() const { + return isBinaryOperator() || + TokenKind == tok::oper_postfix || + TokenKind == tok::oper_prefix; + } + + /// Returns true if this token is not an operator. + bool isNotOperator() const { + return !isOperator(); + } + + /// Print the leading trivia, text, and trailing trivia of this token to + /// the provided output stream. + void print(llvm::raw_ostream &OS, unsigned Indent = 0) const { + for (const auto &Leader : LeadingTrivia) { + Leader.print(OS); + } + + if (!isMissing()) { + OS << getText(); + } + + for (const auto &Trailer : TrailingTrivia) { + Trailer.print(OS); + } + } + + /// Advance the provided AbsolutePosition by the token's full width and + /// return the AbsolutePosition of the start of the token's nontrivial text. + AbsolutePosition accumulateAbsolutePosition(AbsolutePosition &Pos) const; + + /// Dump the textual representation of this token's kind. + void dumpKind(llvm::raw_ostream &OS) const; + + /// Dump the layout of this token: its leading trivia, kind, text, and + /// trailing trivia. + void dump(llvm::raw_ostream &OS, unsigned Indent = 0) const; + + static bool classof(const RawSyntax *RS) { + return RS->Kind == SyntaxKind::Token; + } +}; + +} // end namespace syntax +} // end namespace swift + +#endif // SWIFT_SYNTAX_RAWTOKENSYNTAX_H diff --git a/include/swift/Syntax/Serialization/SyntaxSerialization.h b/include/swift/Syntax/Serialization/SyntaxSerialization.h new file mode 100644 index 00000000000..e72797b9006 --- /dev/null +++ b/include/swift/Syntax/Serialization/SyntaxSerialization.h @@ -0,0 +1,225 @@ +//===--- SyntaxSerialization.h - Swift Syntax Serialization -----*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file provides the serialization of RawSyntax nodes and their +// constituent parts to JSON. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SYNTAX_SERIALIZATION_SYNTAXSERIALIZATION_H +#define SWIFT_SYNTAX_SERIALIZATION_SYNTAXSERIALIZATION_H + +#include "swift/Syntax/RawSyntax.h" +#include "swift/Basic/JSONSerialization.h" +#include "swift/Basic/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include + +namespace swift { +namespace json { + +/// Serialization traits for SourcePresence. +template <> +struct ScalarEnumerationTraits { + static void enumeration(json::Output &out, syntax::SourcePresence &value) { + out.enumCase(value, "Present", syntax::SourcePresence::Present); + out.enumCase(value, "Missing", syntax::SourcePresence::Missing); + } +}; + +/// Serialization traits for SyntaxKind. +template <> +struct ScalarEnumerationTraits { + static void enumeration(Output &out, syntax::SyntaxKind &value) { +#define DEFINE_MAP(Id) \ + out.enumCase(value, #Id, syntax::SyntaxKind::Id); +#define SYNTAX(Id, Parent) DEFINE_MAP(Id) +#define SYNTAX_COLLECTION(Id, Element) DEFINE_MAP(Id) +#include "swift/Syntax/SyntaxKinds.def" + } +}; + +/// Serialization traits for swift::tok. +template <> +struct ScalarEnumerationTraits { + static void enumeration(Output &out, tok &value) { +#define EXPAND(Str, Case) \ + out.enumCase(value, Str, Case); +#define LITERAL(X) EXPAND(#X, tok::X) +#define MISC(X) EXPAND(#X, tok::X) +#define KEYWORD(X) EXPAND("kw_" #X, tok::kw_##X) +#define PUNCTUATOR(X, Y) EXPAND(#X, tok::X) +#define POUND_KEYWORD(X) EXPAND("pound_" #X, tok::pound_##X) +#include "swift/Syntax/TokenKinds.def" + } +}; + +/// Serialization traits for TriviaPiece. +/// - All trivia pieces will have a "kind" key that contains the serialized +/// name of the trivia kind. +/// - Comment trivia will have the associated text of the comment under the +/// "value" key. +/// - All other trivia will have the associated integer count of their +/// occurrences under the "value" key. +template<> +struct ObjectTraits { + static void mapping(Output &out, syntax::TriviaPiece &value) { + out.mapRequired("kind", value.Kind); + switch (value.Kind) { + case syntax::TriviaKind::Space: + case syntax::TriviaKind::Tab: + case syntax::TriviaKind::VerticalTab: + case syntax::TriviaKind::Formfeed: + case syntax::TriviaKind::Newline: + case syntax::TriviaKind::Backtick: + out.mapRequired("value", value.Count); + break; + case syntax::TriviaKind::LineComment: + case syntax::TriviaKind::BlockComment: + case syntax::TriviaKind::DocLineComment: + case syntax::TriviaKind::DocBlockComment: { + auto text = value.Text.str(); + out.mapRequired("value", text); + break; + } + } + } +}; + +/// Serialization traits for TriviaKind. +template <> +struct ScalarEnumerationTraits { + static void enumeration(Output &out, syntax::TriviaKind &value) { + out.enumCase(value, "Space", syntax::TriviaKind::Space); + out.enumCase(value, "Tab", syntax::TriviaKind::Tab); + out.enumCase(value, "VerticalTab", syntax::TriviaKind::VerticalTab); + out.enumCase(value, "Formfeed", syntax::TriviaKind::Formfeed); + out.enumCase(value, "Newline", syntax::TriviaKind::Newline); + out.enumCase(value, "LineComment", syntax::TriviaKind::LineComment); + out.enumCase(value, "BlockComment", syntax::TriviaKind::BlockComment); + out.enumCase(value, "DocLineComment", syntax::TriviaKind::DocLineComment); + out.enumCase(value, "DocBlockComment", syntax::TriviaKind::DocBlockComment); + out.enumCase(value, "Backtick", syntax::TriviaKind::Backtick); + } +}; + +/// Serialization traits for Trivia. +/// Trivia will serialize as an array of the underlying TriviaPieces. +template<> +struct ArrayTraits { + static size_t size(Output &out, syntax::Trivia &seq) { + return seq.Pieces.size(); + } + static syntax::TriviaPiece& element(Output &out, syntax::Trivia &seq, + size_t index) { + return seq.Pieces[index]; + } +}; + +/// An adapter struct that provides a nested structure for token content. +struct TokenDescription { + tok Kind; + StringRef Text; +}; + +/// Serialization traits for TokenDescription. +/// TokenDescriptions always serialized with a token kind, which is +/// the stringified version of their name in the tok:: enum. +/// ``` +/// { +/// "kind": , +/// } +/// ``` +/// +/// For tokens that have some kind of text attached, like literals or +/// identifiers, the serialized form will also have a "text" key containing +/// that text as the value. +template<> +struct ObjectTraits { + static void mapping(Output &out, TokenDescription &value) { + out.mapRequired("kind", value.Kind); + switch (value.Kind) { + case tok::integer_literal: + case tok::floating_literal: + case tok::string_literal: + case tok::unknown: + case tok::code_complete: + case tok::identifier: + case tok::oper_binary_unspaced: + case tok::oper_binary_spaced: + case tok::oper_postfix: + case tok::oper_prefix: + case tok::dollarident: + case tok::comment: + out.mapRequired("text", value.Text); + break; + default: + break; + } + } +}; + +/// Serialization traits for RC. +/// This will be different depending if the raw syntax node is a Token or not. +/// Token nodes will always have this structure: +/// ``` +/// { +/// "tokenKind": { "kind": , "text": }, +/// "leadingTrivia": [ ], +/// "trailingTrivia": [ ], +/// "presence": <"Present" or "Missing"> +/// } +/// ``` +/// All other raw syntax nodes will have this structure: +/// ``` +/// { +/// "kind": , +/// "layout": [ ], +/// "presence": <"Present" or "Missing"> +/// } +/// ``` +template<> +struct ObjectTraits> { + static void mapping(Output &out, RC &value) { + auto kind = value->Kind; + switch (kind) { + case syntax::SyntaxKind::Token: { + auto Tok = cast(value); + auto tokenKind = Tok->getTokenKind(); + auto text = Tok->getText(); + auto description = TokenDescription { tokenKind, text }; + out.mapRequired("tokenKind", description); + + auto leadingTrivia = Tok->LeadingTrivia; + out.mapRequired("leadingTrivia", leadingTrivia); + + auto trailingTrivia = Tok->TrailingTrivia; + out.mapRequired("trailingTrivia", trailingTrivia); + break; + } + default: { + out.mapRequired("kind", kind); + + auto layout = value->Layout; + out.mapRequired("layout", layout); + + break; + } + } + auto presence = value->Presence; + out.mapRequired("presence", presence); + } +}; +} // end namespace json +} // end namespace swift + +#endif /* SWIFT_SYNTAX_SERIALIZATION_SYNTAXSERIALIZATION_H */ diff --git a/include/swift/Syntax/StmtSyntax.h b/include/swift/Syntax/StmtSyntax.h index f0bba83d605..8efb800d1f1 100644 --- a/include/swift/Syntax/StmtSyntax.h +++ b/include/swift/Syntax/StmtSyntax.h @@ -30,20 +30,6 @@ namespace swift { namespace syntax { class ExprSyntax; -class ExprSyntaxData; - -#pragma mark - statement Data - -class StmtSyntaxData : public SyntaxData { -protected: - StmtSyntaxData(RC Raw, const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0) - : SyntaxData(Raw, Parent, IndexInParent) {} -public: - static bool classof(const SyntaxData *S) { - return S->isStmt(); - } -}; #pragma mark - statement API @@ -59,67 +45,31 @@ public: class StmtSyntax : public Syntax { friend class Syntax; protected: - StmtSyntax(const RC Root, const StmtSyntaxData *Data); + virtual void validate() const override {} public: - using DataType = StmtSyntaxData; - static bool classof(const Syntax *S) { + static StmtSyntax makeBlank(); + StmtSyntax(const RC Root, const SyntaxData *Data) + : Syntax(Root, Data) {} + static bool classof(const Syntax *S) { return S->isStmt(); } }; -#pragma mark - unknown-statement Data - -class UnknownStmtSyntaxData : public UnknownSyntaxData { - UnknownStmtSyntaxData(RC Raw, const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); -public: - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::UnknownStmt; - } -}; - #pragma mark - unknown-statement API class UnknownStmtSyntax : public UnknownSyntax { - friend class SyntaxData; - friend class UnknownStmtSyntaxData; friend class LegacyASTTransformer; - using DataType = UnknownStmtSyntaxData; - - UnknownStmtSyntax(const RC Root, - const UnknownStmtSyntaxData *Data); - + virtual void validate() const override; public: + static UnknownStmtSyntax makeBlank(); + UnknownStmtSyntax(const RC Root, const SyntaxData *Data) + : UnknownSyntax(Root, Data) {} static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::UnknownStmt; } }; -#pragma mark - -#pragma mark code-block Data - -class CodeBlockStmtSyntaxData final : public StmtSyntaxData { - friend class SyntaxData; - friend class CodeBlockStmtSyntax; - friend struct SyntaxFactory; - - CodeBlockStmtSyntaxData(RC Raw, const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); -public: - static bool classof(const SyntaxData *SD) { - return SD->getKind() == SyntaxKind::CodeBlockStmt; - } -}; - #pragma mark - #pragma mark code-block API @@ -131,17 +81,20 @@ class CodeBlockStmtSyntax : public StmtSyntax { RightBrace, }; friend struct SyntaxFactory; - friend class CodeBlockStmtSyntaxData; friend class FunctionDeclSyntax; - CodeBlockStmtSyntax(const RC Root, CodeBlockStmtSyntaxData *Data); - public: + + virtual void validate() const override; + static CodeBlockStmtSyntax makeBlank(); + CodeBlockStmtSyntax(const RC Root, const SyntaxData *Data) + : StmtSyntax(Root, Data) {} + /// Returns the left brace of the code block. - RC getLeftBraceToken() const; + TokenSyntax getLeftBraceToken() const; /// Returns a new `CodeBlockSyntax` with the specified left brace token. - CodeBlockStmtSyntax withLeftBraceToken(RC NewLeftBrace) const; + CodeBlockStmtSyntax withLeftBraceToken(TokenSyntax NewLeftBrace) const; /// Return the n-th element in the code block. Syntax getElement(size_t n) const; @@ -156,288 +109,146 @@ public: withElements(const std::vector NewElements) const; /// Returns the right brace of the code block. - RC getRightBraceToken() const; + TokenSyntax getRightBraceToken() const; /// Returns a new `CodeBlockSyntax` with the specified right brace token. - CodeBlockStmtSyntax withRightBraceToken(RC NewRightBraces) const; + CodeBlockStmtSyntax withRightBraceToken(TokenSyntax NewRightBraces) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::CodeBlockStmt; } }; -#pragma mark - -#pragma mark statements Data - -using StmtListSyntaxData = - SyntaxCollectionData; - -#pragma mark - -#pragma mark statements API - -/// statements -> statement -/// | statement statements -class StmtListSyntax final - : public SyntaxCollection { - friend struct SyntaxFactory; - friend class Syntax; - friend class SyntaxData; - friend class FunctionDeclSyntax; - - using DataType = StmtListSyntaxData; - - StmtListSyntax(const RC Root, const DataType *Data) - : SyntaxCollection(Root, Data) {} - -public: - static bool classof(const Syntax *S) { - return S->getKind() == SyntaxKind::StmtList; - } -}; - -#pragma mark - -#pragma mark fallthrough-statement Data - -class FallthroughStmtSyntaxData final : public StmtSyntaxData { - friend class SyntaxData; - friend class FallthroughStmtSyntax; - friend struct SyntaxFactory; - - FallthroughStmtSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); - -public: - static bool classof(const SyntaxData *SD) { - return SD->getKind() == SyntaxKind::FallthroughStmt; - } -}; - #pragma mark - #pragma mark fallthrough-statement API /// fallthrough-statement -> 'fallthrough' class FallthroughStmtSyntax : public StmtSyntax { friend struct SyntaxFactory; - friend class SyntaxData; - friend class FallthroughStmtSyntaxData; - - using DataType = FallthroughStmtSyntaxData; - + enum class Cursor : CursorIndex { FallthroughKeyword, }; - FallthroughStmtSyntax(const RC Root, - const FallthroughStmtSyntaxData *Data); - - static FallthroughStmtSyntax make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static FallthroughStmtSyntax makeBlank(); + virtual void validate() const override; public: + static FallthroughStmtSyntax makeBlank(); + FallthroughStmtSyntax(const RC Root, const SyntaxData *Data) + : StmtSyntax(Root, Data) {} /// Get the 'fallthrough' keyword associated comprising this /// fallthrough statement. - RC getFallthroughKeyword() const; + TokenSyntax getFallthroughKeyword() const; /// Return a new FallthroughStmtSyntax with the given fallthrough /// keyword. FallthroughStmtSyntax - withFallthroughKeyword(RC NewFallthroughKeyword) const; + withFallthroughKeyword(TokenSyntax NewFallthroughKeyword) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::FallthroughStmt; } }; -#pragma mark - break-statement Data - -class BreakStmtSyntaxData : public StmtSyntaxData { - friend class SyntaxData; - friend class BreakStmtSyntax; - friend struct SyntaxFactory; - BreakStmtSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); - -public: - static bool classof(const SyntaxData *SD) { - return SD->getKind() == SyntaxKind::BreakStmt; - } - -}; - #pragma mark - break-statement API /// break-statement -> 'break' label-name? /// label-name -> identifier class BreakStmtSyntax : public StmtSyntax { friend struct SyntaxFactory; - friend class BreakStmtSyntaxData; - friend class SyntaxData; - - using DataType = BreakStmtSyntaxData; enum class Cursor : CursorIndex { BreakKeyword, Label }; - BreakStmtSyntax(const RC Root, - BreakStmtSyntaxData *Data); + virtual void validate() const override; - static BreakStmtSyntax make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static BreakStmtSyntax makeBlank(); public: + static BreakStmtSyntax makeBlank(); + BreakStmtSyntax(const RC Root, const SyntaxData *Data) + : StmtSyntax(Root, Data) {} /// Return the 'break' keyword associated with this break statement. - RC getBreakKeyword() const; + TokenSyntax getBreakKeyword() const; /// Return a new `BreakStmtSyntax` with the given 'break' keyword. - BreakStmtSyntax withBreakKeyword(RC NewBreakKeyword) const; + BreakStmtSyntax withBreakKeyword(TokenSyntax NewBreakKeyword) const; /// Return the destination label of this break statement. If it doesn't /// have one, the token is marked as missing. - RC getLabel() const; + TokenSyntax getLabel() const; /// Return a new `BreakStmtSyntax` with the given destination label. - BreakStmtSyntax withLabel(RC NewLabel) const; + BreakStmtSyntax withLabel(TokenSyntax NewLabel) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::BreakStmt; } }; -#pragma mark - continue-statement Data - -class ContinueStmtSyntaxData : public StmtSyntaxData { - friend class SyntaxData; - friend class ContinueStmtSyntax; - friend struct SyntaxFactory; - ContinueStmtSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); - -public: - static bool classof(const SyntaxData *SD) { - return SD->getKind() == SyntaxKind::ContinueStmt; - } - -}; - #pragma mark - continue-statement API /// continue-statement -> 'continue' label-name? /// label-name -> identifier class ContinueStmtSyntax : public StmtSyntax { friend struct SyntaxFactory; - friend class ContinueStmtSyntaxData; - friend class SyntaxData; - - using DataType = ContinueStmtSyntaxData; enum class Cursor : CursorIndex { ContinueKeyword, Label }; - ContinueStmtSyntax(const RC Root, - ContinueStmtSyntaxData *Data); + virtual void validate() const override; - static ContinueStmtSyntax make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static ContinueStmtSyntax makeBlank(); public: + static ContinueStmtSyntax makeBlank(); + ContinueStmtSyntax(const RC Root, const SyntaxData *Data) + : StmtSyntax(Root, Data) {} /// Return the 'continue' keyword associated with this continue statement. - RC getContinueKeyword() const; + TokenSyntax getContinueKeyword() const; /// Return a new `ContinueStmtSyntax` with the given 'continue' keyword. - ContinueStmtSyntax withContinueKeyword(RC NewBreakKeyword) const; + ContinueStmtSyntax withContinueKeyword(TokenSyntax NewBreakKeyword) const; /// Return the destination label of this break statement. If it doesn't /// have one, the token is marked as continue. - RC getLabel() const; + TokenSyntax getLabel() const; /// Return a new `ContinueStmtSyntax` with the given destination label. - ContinueStmtSyntax withLabel(RC NewLabel) const; + ContinueStmtSyntax withLabel(TokenSyntax NewLabel) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::ContinueStmt; } }; -#pragma mark - return-statement Data - -class ReturnStmtSyntaxData : public StmtSyntaxData { - friend class SyntaxData; - friend class ReturnStmtSyntax; - friend struct SyntaxFactory; - - RC CachedExpression; - - ReturnStmtSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); - -public: - static bool classof(const SyntaxData *SD) { - return SD->getKind() == SyntaxKind::ReturnStmt; - } - -}; - #pragma mark - return-statement API /// return-statement -> 'return' expression? ';'? class ReturnStmtSyntax : public StmtSyntax { friend struct SyntaxFactory; - friend class ReturnStmtSyntaxData; - friend class SyntaxData; friend class Syntax; - using DataType = ReturnStmtSyntaxData; - enum class Cursor : CursorIndex { ReturnKeyword, Expression }; - ReturnStmtSyntax(const RC Root, - const ReturnStmtSyntaxData *Data); + virtual void validate() const override; - static ReturnStmtSyntax make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static ReturnStmtSyntax makeBlank(); public: + static ReturnStmtSyntax makeBlank(); + ReturnStmtSyntax(const RC Root, const SyntaxData *Data) + : StmtSyntax(Root, Data) {} /// Return the 'return' keyword associated with this return statement. - RC getReturnKeyword() const; + TokenSyntax getReturnKeyword() const; /// Return a new `ReturnStmtSyntax` with the given 'return' keyword. - ReturnStmtSyntax withReturnKeyword(RC NewReturnKeyword) const; + ReturnStmtSyntax withReturnKeyword(TokenSyntax NewReturnKeyword) const; /// Return the expression of this return statement. Optional getExpression() const; diff --git a/include/swift/Syntax/Syntax.h b/include/swift/Syntax/Syntax.h index d1cc24da360..bada4898a76 100644 --- a/include/swift/Syntax/Syntax.h +++ b/include/swift/Syntax/Syntax.h @@ -23,6 +23,7 @@ #ifndef SWIFT_SYNTAX_SYNTAX_H #define SWIFT_SYNTAX_SYNTAX_H +#include "swift/Syntax/SyntaxData.h" #include "swift/Syntax/References.h" #include "swift/Syntax/RawSyntax.h" #include "swift/Syntax/Trivia.h" @@ -36,9 +37,13 @@ namespace sema { } namespace syntax { -const auto NoParent = llvm::None; +template +SyntaxNode make(RC Raw) { + auto Data = SyntaxData::make(Raw); + return { Data, Data.get() }; +} -class SyntaxData; +const auto NoParent = llvm::None; /// The main handle for syntax nodes - subclasses contain all public /// structured editing APIs. @@ -49,7 +54,6 @@ class SyntaxData; /// their children. class Syntax { friend struct SyntaxFactory; - friend class SyntaxData; friend class LegacyASTTransformer; friend class sema::Semantics; @@ -67,16 +71,16 @@ protected: /// lazily created. mutable const SyntaxData *Data; - template - typename SyntaxNode::DataType *getUnsafeData() const { - auto Casted = cast(Data); - return const_cast(Casted); - } + /// Subclasses override this to ensure their structure matches expectations. + virtual void validate() const {}; public: - using DataType = SyntaxData; + Syntax(const RC Root, const SyntaxData *Data) + : Root(Root), Data(Data) { + this->validate(); + } - Syntax(const RC Root, const SyntaxData *Data); + virtual ~Syntax() {} /// Get the kind of syntax. SyntaxKind getKind() const; @@ -91,10 +95,8 @@ public: } /// Get the Data for this Syntax node. - template - typename T::DataType &getData() const { - assert(is() && "getData() node of incompatible type!"); - return *reinterpret_cast(Data); + const SyntaxData &getData() const { + return *Data; } const SyntaxData *getDataPointer() const { @@ -106,7 +108,7 @@ public: template T castTo() const { assert(is() && "castTo() node of incompatible type!"); - return T { Root, reinterpret_cast(Data) }; + return T { Root, Data }; } /// If this Syntax node is of the right kind, cast and return it, diff --git a/include/swift/Syntax/SyntaxCollection.h b/include/swift/Syntax/SyntaxCollection.h index 52cd7fca821..d3a63d11d80 100644 --- a/include/swift/Syntax/SyntaxCollection.h +++ b/include/swift/Syntax/SyntaxCollection.h @@ -14,11 +14,13 @@ #define SWIFT_SYNTAX_SYNTAXCOLLECTION_H #include "swift/Syntax/Syntax.h" -#include "swift/Syntax/SyntaxCollectionData.h" namespace swift { namespace syntax { +template +class SyntaxCollection; + template struct SyntaxCollectionIterator { const SyntaxCollection &Collection; @@ -50,12 +52,10 @@ struct SyntaxCollectionIterator { template class SyntaxCollection : public Syntax { friend struct SyntaxFactory; - friend class SyntaxData; friend class Syntax; - using DataType = SyntaxCollectionData; private: - static RC + static RC makeData(std::vector &Elements) { RawSyntax::LayoutList List; for (auto &Elt : Elements) { @@ -63,15 +63,19 @@ private: } auto Raw = RawSyntax::make(CollectionKind, List, SourcePresence::Present); - return DataType::make(Raw); + return SyntaxData::make(Raw); } -protected: - SyntaxCollection(const RC Root, const DataType *Data) - : Syntax(Root, Data) {} - public: + static SyntaxCollection makeBlank() { + auto Raw = RawSyntax::make(CollectionKind, {}, SourcePresence::Present); + return make>(Raw); + } + + SyntaxCollection(const RC Root, const SyntaxData *Data) + : Syntax(Root, Data) {} + /// Returns true if the collection is empty. bool empty() const { return size() == 0; @@ -104,22 +108,8 @@ public: assert(Index < size()); assert(!empty()); - auto RawElement = getRaw()->Layout[Index]; - auto *MyData = getUnsafeData>(); - - if (auto Data = MyData->CachedElements[Index].get()) { - return Element { Root, Data }; - } - - auto &ChildPtr = *reinterpret_cast*>( - MyData->CachedElements.data() + Index); - - SyntaxData::realizeSyntaxNode(ChildPtr, RawElement, MyData, Index); - - return Element { - Root, - MyData->CachedElements[Index].get() - }; + auto ChildData = Data->getChild(Index); + return Element { Root, ChildData.get() }; } /// Return a new collection with the given element added to the end. @@ -201,6 +191,12 @@ public: } }; +#define SYNTAX(Id, Super) +#define SYNTAX_COLLECTION(Id, Element) \ +class Element; \ +using Id##Syntax = SyntaxCollection; +#include "swift/Syntax/SyntaxKinds.def" + } // end namespace syntax } // end namespace swift diff --git a/include/swift/Syntax/SyntaxCollectionData.h b/include/swift/Syntax/SyntaxCollectionData.h deleted file mode 100644 index 457e36cb8b6..00000000000 --- a/include/swift/Syntax/SyntaxCollectionData.h +++ /dev/null @@ -1,73 +0,0 @@ -//===--- SyntaxCollectionData.h ---------------------------------*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_SYNTAX_SYNTAXCOLLECTIONDATA_H -#define SWIFT_SYNTAX_SYNTAXCOLLECTIONDATA_H - -#include "swift/Syntax/SyntaxData.h" - -namespace swift { -namespace syntax { - -template -class SyntaxCollection; - -template -class SyntaxCollectionData : public SyntaxData { - friend class SyntaxCollection; - std::vector> CachedElements; - - friend struct SyntaxFactory; - friend class SyntaxData; - friend class FunctionCallExprSyntaxBuilder; - - - static RC> - make(RC Raw, const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0) { - - return RC> { - new SyntaxCollectionData { - Raw, Parent, IndexInParent - } - }; - } - - static RC> makeBlank() { - auto Raw = RawSyntax::make(CollectionKind, {}, SourcePresence::Present); - return make(Raw); - } - -protected: - SyntaxCollectionData(RC Raw, const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0) - : SyntaxData(Raw, Parent, IndexInParent), - CachedElements(Raw->Layout.size(), nullptr) { - assert(Raw->Kind == CollectionKind); - } - -public: - static bool classof(const SyntaxData *SD) { - return SD->getKind() == CollectionKind; - } -}; - -#define SYNTAX(Id, Parent) -#define SYNTAX_COLLECTION(Id, Element) \ - class Element; \ - using Id##SyntaxData = SyntaxCollectionData; -#include "swift/Syntax/SyntaxKinds.def" - -} // end namespace syntax -} // end namespace swift - -#endif diff --git a/include/swift/Syntax/SyntaxData.h b/include/swift/Syntax/SyntaxData.h index 674b47e2757..8f0bd986991 100644 --- a/include/swift/Syntax/SyntaxData.h +++ b/include/swift/Syntax/SyntaxData.h @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// // -// This file defines the SyntaxData interface, the base type for the instance +// This file defines the SyntaxData interface, the type for the instance // data for Syntax nodes. // // Effectively, these provide two main things to a Syntax node - parental @@ -39,9 +39,9 @@ #ifndef SWIFT_SYNTAX_SYNTAXDATA_H #define SWIFT_SYNTAX_SYNTAXDATA_H +#include "swift/Syntax/AtomicCache.h" #include "swift/Syntax/RawSyntax.h" #include "swift/Syntax/References.h" -#include "swift/Syntax/Syntax.h" #include "llvm/ADT/DenseMap.h" #include @@ -49,20 +49,23 @@ namespace swift { namespace syntax { -class Syntax; - -/// The base class for holding parented syntax. +/// The class for holding parented syntax. /// -/// This structure and subclasses thereof should not contain significant public +/// This structure should not contain significant public /// API or internal modification API. /// /// This is only for holding a strong reference to the RawSyntax, a weak /// reference to the parent, and, in subclasses, lazily created strong /// references to non-terminal child nodes. -class SyntaxData : public llvm::ThreadSafeRefCountedBase { +class SyntaxData final : public llvm::ThreadSafeRefCountedBase { friend struct SyntaxFactory; #define SYNTAX(Id, Parent) friend class Id##Syntax; #include "swift/Syntax/SyntaxKinds.def" + + using RootDataPair = std::pair, RC>; + + llvm::SmallVector, 10> Children; + public: /// The shared raw syntax representing this syntax data node. const RC Raw; @@ -80,123 +83,73 @@ public: SyntaxData(RC Raw, const SyntaxData *Parent = nullptr, CursorIndex IndexInParent = 0) - : Raw(Raw), Parent(Parent), IndexInParent(IndexInParent) {} + : Raw(Raw), Parent(Parent), IndexInParent(IndexInParent) { + if (Raw) { + for (size_t I = 0; I < Raw->Layout.size(); ++I) { + Children.push_back(AtomicCache()); + } + } + } + + /// Constructs a SyntaxNode by replacing `self` and recursively building + /// the parent chain up to the root. + template + SyntaxNode replaceSelf(const RC NewRaw) const { + auto NewRootAndData = replaceSelf(NewRaw); + return { NewRootAndData.first, NewRootAndData.second.get() }; + } /// With a new RawSyntax node, create a new node from this one and /// recursively rebuild the parental chain up to the root. /// /// DO NOT expose this as public API. - template - SyntaxNode replaceSelf(RC NewRaw) const { - auto NewMe = SyntaxNode::DataType::make(NewRaw, nullptr, IndexInParent); + RootDataPair replaceSelf(const RC NewRaw) const { if (hasParent()) { - auto NewRootAndParent = getParent().getValue() - ->replaceChild(NewRaw, IndexInParent); - NewMe->Parent = NewRootAndParent.Data; - return SyntaxNode { - NewRootAndParent.Root, - cast(NewMe.get()) - }; + auto NewRootAndParent = + getParent().getValue()->replaceChild(NewRaw, IndexInParent); + auto NewMe = NewRootAndParent.second->getChild(IndexInParent); + return { NewRootAndParent.first, NewMe.get() }; } else { - return SyntaxNode { - NewMe, - cast(NewMe.get()) - }; + auto NewMe = make(NewRaw, nullptr, IndexInParent); + return { NewMe, NewMe.get() }; } } - /// Unsafely instantiate a child within another node. - /// - /// DANGER! - /// - /// Scary thread-safe code here. This should only be used for internally - /// mutating cached children! - /// - /// Why do we need this? - /// - ___SyntaxData nodes should have pointer identity. - /// - We only want to construct parented, realized child nodes as - /// ___SyntaxData when asked. - /// - /// For example, if we have a ReturnStmtSyntax, and ask for its returned - /// expression for the first time with getExpression(), two nodes can race - /// to create and set the cached expression. - /// - /// - /// Looking at an example - say we have a ReturnStmtSyntaxData. - /// - /// ReturnStmtSyntaxData = { - /// RC Raw = { - /// RC { SyntaxKind::SomeExpression, ... } - /// } - /// RC CachedExpression = { 0 }; - /// } - /// - /// We pretend that `CachedExpression` is a std::atomic &, so that - /// we can safely instantiate that field using the RawSyntax for the - /// expression, i.e. getRaw()->getChild(ReturnStmtSyntax::Cursor::Expression)) - template - static - void realizeSyntaxNode(std::atomic &Child, - RC RawChild, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - // We rely on the fact that an RC<___SyntaxData> is pointer-sized, which - // means we can atomically compare-exchange the child field. - // If we can't do that, we can't pretend it's a uintptr_t and use its - // compare_exchange_strong. - static_assert( - sizeof(uintptr_t) == sizeof(RC), - "Can't safely atomically replace a child SyntaxData node " - "for caching! This is the end of the world!"); - - if (Child == 0) { - // We expect the uncached value to wrap a nullptr. If another thread - // beats us to caching the child, it'll be non-null, so we would - // leave it alone. - uintptr_t Expected = 0; - - // Make a RC at RefCount == 1, which we'll try to - // atomically swap in. - RC Data = - cast( - SyntaxData::makeDataFromRaw(RawChild, Parent, IndexInParent)); - - // Try to swap in raw pointer value. - auto SuccessfullySwapped = - Child.compare_exchange_strong(Expected, - reinterpret_cast(Data.get())); - - // If we won, then leave the RefCount == 1. - if (SuccessfullySwapped) { - Data.resetWithoutRelease(); - } - - // Otherwise, the Data we just made is unfortunately useless. - // Let it die on this scope exit after its terminal release. - } + /// Create the data for a child node with the raw syntax in our layout + /// at the provided index. + /// DO NOT expose this as public API. + RC realizeSyntaxNode(CursorIndex Index) const { + auto RawChild = Raw->Layout.at(Index); + return SyntaxData::make(RawChild, this, Index); } /// Replace a child in the raw syntax and recursively rebuild the /// parental chain up to the root. /// - /// This is the effective private implementation of all setters in - /// subclasses of `SyntaxData`. - /// /// DO NOT expose this as public API. template - SyntaxNode replaceChild(RC RawChild, + SyntaxNode replaceChild(const RC RawChild, CursorType ChildCursor) const { + auto NewRootAndParent = replaceChild(RawChild, ChildCursor); + return SyntaxNode { + NewRootAndParent.first, + NewRootAndParent.second.get() + }; + } + + /// Replace a child in the raw syntax and recursively rebuild the + /// parental chain up to the root. + /// + /// DO NOT expose this as public API. + template + RootDataPair replaceChild(const RC RawChild, + CursorType ChildCursor) const { auto NewRaw = Raw->replaceChild(ChildCursor, RawChild); - return replaceSelf(NewRaw); + return replaceSelf(NewRaw); } public: - static RC makeDataFromRaw(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent); - static RC make(RC Raw, const SyntaxData *Parent = nullptr, CursorIndex IndexInParent = 0); @@ -216,7 +169,7 @@ public: if (Parent != nullptr) { return Parent; } - return NoParent; + return llvm::None; } /// Returns true if this syntax node has a parent. @@ -230,6 +183,51 @@ public: return IndexInParent; } + /// Returns the number of children this SyntaxData represents. + size_t getNumChildren() const { + return Raw->Layout.size(); + } + + /// Gets the child at the index specified by the provided cursor, + /// lazily creating it if necessary. + template + RC getChild(CursorType Cursor) const { + return getChild((size_t)cursorIndex(Cursor)); + } + + /// Gets the child at the specified index in this data's children array. + /// Why do we need this? + /// - SyntaxData nodes should have pointer identity. + /// - We only want to construct parented, realized child nodes as + /// SyntaxData when asked. + /// + /// For example, if we have a ReturnStmtSyntax, and ask for its returned + /// expression for the first time with getExpression(), two nodes can race + /// to create and set the cached expression. + /// + /// Looking at an example - say we have a SyntaxData. + /// + /// SyntaxData = { + /// RC Raw = { + /// RC { SyntaxKind::Token, tok::return_kw, "return" }, + /// RC { SyntaxKind::SomeExpression, ... } + /// } + /// llvm::SmallVector, 10> Children { + /// AtomicCache { RC = nullptr; }, + /// AtomicCache { RC = nullptr; }, + /// } + /// } + /// + /// If we wanted to safely create the 0th child, an instance of TokenSyntax, + /// then we ask the AtomicCache in that position to realize its value and + /// cache it. This is safe because AtomicCache only ever mutates its cache + /// one time -- the first initialization that wins a compare_exchange_strong. + RC getChild(size_t Index) const { + return Children[Index].getOrCreate([&]() { + return realizeSyntaxNode(Index); + }); + } + /// Returns true if the data node represents type syntax. bool isType() const; @@ -242,6 +240,9 @@ public: /// Returns true if the data node represents expression syntax. bool isExpr() const; + /// Returns true if the data node represents pattern syntax. + bool isPattern() const; + /// Returns true if this syntax is of some "unknown" kind. bool isUnknown() const; diff --git a/include/swift/Syntax/SyntaxFactory.h b/include/swift/Syntax/SyntaxFactory.h index 1e09b3e1dd6..0b629b84833 100644 --- a/include/swift/Syntax/SyntaxFactory.h +++ b/include/swift/Syntax/SyntaxFactory.h @@ -42,13 +42,18 @@ class DeclSyntax; class ExprSyntax; class StmtSyntax; class UnknownSyntax; -struct TokenSyntax; +struct RawTokenSyntax; -/// The Syntax builder - the one-stop shop for making new Syntax nodes. +/// The Syntax factory - the one-stop shop for making new Syntax nodes. struct SyntaxFactory { + /// Make any kind of token. + static TokenSyntax + makeToken(tok Kind, OwnedString Text, SourcePresence Presence, + const Trivia &LeadingTrivia, const Trivia &TrailingTrivia); + /// Collect a list of tokens into a piece of "unknown" syntax. static UnknownSyntax - makeUnknownSyntax(llvm::ArrayRef> Tokens); + makeUnknownSyntax(llvm::ArrayRef Tokens); #pragma mark - Declarations @@ -56,8 +61,8 @@ struct SyntaxFactory { /// Make a declaration modifier with the specified elements. static DeclModifierSyntax - makeDeclModifier(RC Name, RC LeftParen, - RC Argument, RC RightParen); + makeDeclModifier(TokenSyntax Name, TokenSyntax LeftParen, + TokenSyntax Argument, TokenSyntax RightParen); /// Make a declaration modifier with all missing elements. static DeclModifierSyntax makeBlankDeclModifier(); @@ -73,19 +78,19 @@ struct SyntaxFactory { /// Make a struct declaration with the specified elements. static StructDeclSyntax - makeStructDecl(RC StructToken, RC Identifier, + makeStructDecl(TokenSyntax StructToken, TokenSyntax Identifier, Syntax GenericParameters, Syntax WhereClause, - RC LeftBrace, Syntax DeclMembers, - RC RightBrace); + TokenSyntax LeftBrace, Syntax DeclMembers, + TokenSyntax RightBrace); /// Make a struct declaration with all missing elements. static StructDeclSyntax makeBlankStructDecl(); /// Make a typealias declaration with the specified elements. static TypeAliasDeclSyntax - makeTypealiasDecl(RC TypealiasToken, RC Identifier, + makeTypealiasDecl(TokenSyntax TypealiasToken, TokenSyntax Identifier, GenericParameterClauseSyntax GenericParams, - RC AssignmentToken, TypeSyntax Type); + TokenSyntax AssignmentToken, TypeSyntax Type); /// Make a typealias declaration with all missing elements. static TypeAliasDeclSyntax makeBlankTypealiasDecl(); @@ -97,8 +102,8 @@ struct SyntaxFactory { static FunctionDeclSyntax makeFunctionDecl(TypeAttributesSyntax Attributes, DeclModifierListSyntax Modifiers, - RC FuncKeyword, - RC Identifier, + TokenSyntax FuncKeyword, + TokenSyntax Identifier, llvm::Optional GenericParams, FunctionSignatureSyntax Signature, llvm::Optional GenericWhereClause, @@ -111,13 +116,13 @@ struct SyntaxFactory { /// Make a function parameter with the given elements. static FunctionParameterSyntax - makeFunctionParameter(RC ExternalName, RC LocalName, - RC Colon, + makeFunctionParameter(TokenSyntax ExternalName, TokenSyntax LocalName, + TokenSyntax Colon, llvm::Optional ParameterTypeSyntax, - RC Ellipsis, - RC Equal, + TokenSyntax Ellipsis, + TokenSyntax Equal, llvm::Optional DefaultValue, - RC TrailingComma); + TokenSyntax TrailingComma); /// Make a function parameter with all elements marked as missing. static FunctionParameterSyntax makeBlankFunctionParameter(); @@ -135,11 +140,11 @@ struct SyntaxFactory { /// Make a function signature with the given elements. static FunctionSignatureSyntax - makeFunctionSignature(RC LeftParen, + makeFunctionSignature(TokenSyntax LeftParen, FunctionParameterListSyntax ParameterList, - RC RightParen, - RC ThrowsOrRethrows, - RC Arrow, + TokenSyntax RightParen, + TokenSyntax ThrowsOrRethrows, + TokenSyntax Arrow, TypeAttributesSyntax ReturnTypeAttributes, TypeSyntax ReturnTypeSyntax); @@ -156,16 +161,16 @@ struct SyntaxFactory { /// Make a code block with the specified elements. static CodeBlockStmtSyntax - makeCodeBlock(RC LeftBraceToken, + makeCodeBlock(TokenSyntax LeftBraceToken, StmtListSyntax Elements, - RC RightBraceToken); + TokenSyntax RightBraceToken); /// Make a code block with all missing elements. static CodeBlockStmtSyntax makeBlankCodeBlock(); /// Make a fallthrough statement with the give `fallthrough` keyword. static FallthroughStmtSyntax - makeFallthroughStmt(RC FallthroughKeyword); + makeFallthroughStmt(TokenSyntax FallthroughKeyword); /// Make a fallthrough statement with the `fallthrough` keyword /// marked as missing. @@ -174,7 +179,7 @@ struct SyntaxFactory { /// Make a break statement with the give `break` keyword and /// destination label. static BreakStmtSyntax - makeBreakStmt(RC BreakKeyword, RC Label); + makeBreakStmt(TokenSyntax BreakKeyword, TokenSyntax Label); /// Make a break statement with the `break` keyword /// and destination label marked as missing. @@ -183,7 +188,7 @@ struct SyntaxFactory { /// Make a continue statement with the given `continue` keyword and /// destination label. static ContinueStmtSyntax - makeContinueStmt(RC ContinueKeyword, RC Label); + makeContinueStmt(TokenSyntax ContinueKeyword, TokenSyntax Label); /// Make a continue statement with the `continue` keyword /// and destination label marked as missing. @@ -192,7 +197,7 @@ struct SyntaxFactory { /// Make a return statement with the given `return` keyword and returned /// expression. static ReturnStmtSyntax - makeReturnStmt(RC ReturnKeyword, ExprSyntax ReturnedExpression); + makeReturnStmt(TokenSyntax ReturnKeyword, ExprSyntax ReturnedExpression); /// Make a return statement with the `return` keyword and return expression /// marked as missing. @@ -208,7 +213,7 @@ struct SyntaxFactory { /// Make an integer literal with the given '+'/'-' sign and string of digits. static IntegerLiteralExprSyntax - makeIntegerLiteralExpr(RC Sign, RC Digits); + makeIntegerLiteralExpr(TokenSyntax Sign, TokenSyntax Digits); /// Make an integer literal with the sign and string of digits marked /// as missing. @@ -217,7 +222,7 @@ struct SyntaxFactory { /// Make a symbolic reference with the given identifier and optionally a /// generic argument clause. static SymbolicReferenceExprSyntax - makeSymbolicReferenceExpr(RC Identifier, + makeSymbolicReferenceExpr(TokenSyntax Identifier, llvm::Optional GenericArgs); /// Make a symbolic reference expression with the identifier and @@ -230,9 +235,9 @@ struct SyntaxFactory { /// Make a function call argument based on an expression with the /// given elements. static FunctionCallArgumentSyntax - makeFunctionCallArgument(RC Label, RC Colon, + makeFunctionCallArgument(TokenSyntax Label, TokenSyntax Colon, ExprSyntax ExpressionArgument, - RC TrailingComma); + TokenSyntax TrailingComma); /// Make a function call argument list with the given arguments. static FunctionCallArgumentListSyntax @@ -244,9 +249,9 @@ struct SyntaxFactory { /// Make a function call expression with the given elements. static FunctionCallExprSyntax - makeFunctionCallExpr(ExprSyntax CalledExpr, RC LeftParen, + makeFunctionCallExpr(ExprSyntax CalledExpr, TokenSyntax LeftParen, FunctionCallArgumentListSyntax Arguments, - RC RightParen); + TokenSyntax RightParen); /// Make a function call expression with all elements marked as missing. static FunctionCallExprSyntax makeBlankFunctionCallExpr(); @@ -254,173 +259,173 @@ struct SyntaxFactory { #pragma mark - Tokens /// Make a 'static' keyword with the specified leading and trailing trivia. - static RC makeStaticKeyword(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeStaticKeyword(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make a 'public' keyword with the specified leading and trailing trivia. - static RC makePublicKeyword(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makePublicKeyword(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make a 'func' keyword with the specified leading and trailing trivia. - static RC makeFuncKeyword(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeFuncKeyword(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make a 'fallthrough' keyword with the specified leading and /// trailing trivia. - static RC makeFallthroughKeyword(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeFallthroughKeyword(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make an at-sign '@' token with the specified leading and /// trailing trivia. - static RC makeAtSignToken(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeAtSignToken(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make a 'break' keyword with the specified leading and /// trailing trivia. - static RC makeBreakKeyword(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeBreakKeyword(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make a 'continue' keyword with the specified leading and /// trailing trivia. - static RC makeContinueKeyword(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeContinueKeyword(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make a 'return' keyword with the specified leading and /// trailing trivia. - static RC makeReturnKeyword(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeReturnKeyword(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make a left angle '<' token with the specified leading and /// trailing trivia. - static RC makeLeftAngleToken(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeLeftAngleToken(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make a right angle '>' token with the specified leading and /// trailing trivia. - static RC makeRightAngleToken(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeRightAngleToken(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make a left parenthesis '(' token with the specified leading and /// trailing trivia. - static RC makeLeftParenToken(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeLeftParenToken(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make a right parenthesis ')' token with the specified leading and /// trailing trivia. - static RC makeRightParenToken(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeRightParenToken(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make a left brace '{' token with the specified leading and /// trailing trivia. - static RC makeLeftBraceToken(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeLeftBraceToken(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make a right brace '}' token with the specified leading and /// trailing trivia. - static RC makeRightBraceToken(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeRightBraceToken(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make a left square bracket '[' token with the specified leading and /// trailing trivia. - static RC + static TokenSyntax makeLeftSquareBracketToken(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia); /// Make a right square bracket ']' token with the specified leading and /// trailing trivia. - static RC + static TokenSyntax makeRightSquareBracketToken(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia); /// Make a postfix question '?' token with the specified trailing trivia. /// The leading trivia is assumed to be of zero width. - static RC + static TokenSyntax makeQuestionPostfixToken(const Trivia &TrailingTrivia); /// Make an exclamation '!' token with the specified trailing trivia. /// The leading trivia is assumed to be of zero width. - static RC makeExclaimPostfixToken(const Trivia &TrailingTrivia); + static TokenSyntax makeExclaimPostfixToken(const Trivia &TrailingTrivia); /// Make an identifier token with the specified leading and trailing trivia. - static RC makeIdentifier(OwnedString Name, + static TokenSyntax makeIdentifier(OwnedString Name, const Trivia &LeadingTrivia, const Trivia &TrailingTrivia); /// Make a comma ',' token with the specified leading and trailing trivia. - static RC makeCommaToken(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeCommaToken(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make a colon ':' token with the specified leading and trailing trivia. - static RC makeColonToken(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeColonToken(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make a dot '.' token with the specified leading and trailing trivia. - static RC makeDotToken(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeDotToken(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make a 'struct' keyword with the specified leading and trailing trivia. - static RC makeStructKeyword(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeStructKeyword(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make a 'where' keyword with the specified leading and trailing trivia. - static RC makeWhereKeyword(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeWhereKeyword(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make a 'inout' keyword with the specified leading and trailing trivia. - static RC makeInoutKeyword(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeInoutKeyword(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make a 'throws' keyword with the specified leading and trailing trivia. - static RC makeThrowsKeyword(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeThrowsKeyword(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make a 'rethrows' keyword with the specified leading and /// trailing trivia. - static RC makeRethrowsKeyword(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeRethrowsKeyword(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make a 'typealias' keyword with the specified leading and /// trailing trivia. - static RC makeTypealiasKeyword(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeTypealiasKeyword(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make an equal '=' token with the specified leading and /// trailing trivia. - static RC makeEqualToken(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeEqualToken(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make an arrow '->' token with the specified leading and trailing trivia. - static RC makeArrow(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeArrow(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make an equality '==' binary operator with the specified leading and /// trailing trivia. - static RC makeEqualityOperator(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeEqualityOperator(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make the terminal identifier token `Type` - static RC makeTypeToken(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeTypeToken(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make the terminal identifier token `Protocol` - static RC makeProtocolToken(const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeProtocolToken(const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); /// Make a token representing the digits of an integer literal. /// /// Note: This is not a stand-in for the expression, which can contain /// a minus sign. - static RC makeIntegerLiteralToken(OwnedString Digits, - const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia); + static TokenSyntax makeIntegerLiteralToken(OwnedString Digits, + const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia); #pragma mark - Operators /// Make a prefix operator with the given text. - static RC makePrefixOperator(OwnedString Name, - const Trivia &LeadingTrivia); + static TokenSyntax makePrefixOperator(OwnedString Name, + const Trivia &LeadingTrivia); #pragma mark - Types @@ -428,11 +433,11 @@ struct SyntaxFactory { /// Make a type attribute with the specified elements. static TypeAttributeSyntax - makeTypeAttribute(RC AtSignToken, - RC Identifier, - RC LeftParen, + makeTypeAttribute(TokenSyntax AtSignToken, + TokenSyntax Identifier, + TokenSyntax LeftParen, BalancedTokensSyntax BalancedTokens, - RC RightParen); + TokenSyntax RightParen); /// Make a type attribute with all elements marked as missing. static TypeAttributeSyntax makeBlankTypeAttribute(); @@ -446,7 +451,7 @@ struct SyntaxFactory { /// Make a list of balanced tokens. static BalancedTokensSyntax - makeBalancedTokens(RawSyntax::LayoutList Tokens); + makeBalancedTokens(llvm::ArrayRef Tokens); /// Make an empty list of balanced tokens. static BalancedTokensSyntax makeBlankBalancedTokens(); @@ -460,7 +465,7 @@ struct SyntaxFactory { /// Make a generic type identifier. static TypeIdentifierSyntax - makeTypeIdentifier(RC Identifier, + makeTypeIdentifier(TokenSyntax Identifier, GenericArgumentClauseSyntax GenericArgs); /// Make a bare "Any" type. @@ -477,20 +482,20 @@ struct SyntaxFactory { /// Make a tuple type from a type element list and the provided left/right /// paren tokens. static TupleTypeSyntax - makeTupleType(RC LParen, + makeTupleType(TokenSyntax LParen, TupleTypeElementListSyntax Elements, - RC RParen); + TokenSyntax RParen); /// Make a tuple type element of the form 'Name: ElementType' static TupleTypeElementSyntax - makeTupleTypeElement(RC Name, RC Colon, + makeTupleTypeElement(TokenSyntax Name, TokenSyntax Colon, TypeSyntax ElementType, - llvm::Optional> MaybeComma = llvm::None); + llvm::Optional MaybeComma = llvm::None); /// Make a tuple type element without a label. static TupleTypeElementSyntax makeTupleTypeElement(TypeSyntax ElementType, - llvm::Optional> MaybeComma = llvm::None); + llvm::Optional MaybeComma = llvm::None); /// Make a tuple type element list. static TupleTypeElementListSyntax @@ -520,8 +525,8 @@ struct SyntaxFactory { /// Make a metatype type, as in `T.Type` /// `Type` is a terminal token here, not a placeholder for something else. static MetatypeTypeSyntax makeMetatypeType(TypeSyntax BaseType, - RC DotToken, - RC TypeToken); + TokenSyntax DotToken, + TokenSyntax TypeToken); /// Make a metatype type with all elements marked as missing. static MetatypeTypeSyntax makeBlankMetatypeType(); @@ -529,9 +534,9 @@ struct SyntaxFactory { #pragma mark - array-type /// Make a sugared Array type, as in `[MyType]`. - static ArrayTypeSyntax makeArrayType(RC LeftSquareBracket, + static ArrayTypeSyntax makeArrayType(TokenSyntax LeftSquareBracket, TypeSyntax ElementType, - RC RightSquareBracket); + TokenSyntax RightSquareBracket); /// Make an array type with all elements marked as missing. static ArrayTypeSyntax makeBlankArrayType(); @@ -540,9 +545,9 @@ struct SyntaxFactory { /// Make a Dictionary type, as in `[Key : Value]`. static DictionaryTypeSyntax - makeDictionaryType(RC LeftSquareBracket, TypeSyntax KeyType, - RC Colon, TypeSyntax ValueType, - RC RightSquareBracket); + makeDictionaryType(TokenSyntax LeftSquareBracket, TypeSyntax KeyType, + TokenSyntax Colon, TypeSyntax ValueType, + TokenSyntax RightSquareBracket); /// Make an a dictionary type with all elements marked as missing. static DictionaryTypeSyntax makeBlankDictionaryType(); @@ -551,18 +556,18 @@ struct SyntaxFactory { /// Make a function argument type syntax with the specified elements. static FunctionTypeArgumentSyntax - makeFunctionTypeArgument(RC ExternalParameterName, - RC LocalParameterName, + makeFunctionTypeArgument(TokenSyntax ExternalParameterName, + TokenSyntax LocalParameterName, TypeAttributesSyntax TypeAttributes, - RC InoutKeyword, - RC ColonToken, + TokenSyntax InoutKeyword, + TokenSyntax ColonToken, TypeSyntax ParameterTypeSyntax); /// Make a simple function type argument syntax with the given label and /// simple type name. static FunctionTypeArgumentSyntax - makeFunctionTypeArgument(RC LocalParameterName, - RC ColonToken, + makeFunctionTypeArgument(TokenSyntax LocalParameterName, + TokenSyntax ColonToken, TypeSyntax ParameterType); /// Make a simple function type argument syntax with the given simple @@ -578,10 +583,10 @@ struct SyntaxFactory { /// Make a function type, for example, `(Int, Int) throws -> Int` static FunctionTypeSyntax makeFunctionType(TypeAttributesSyntax TypeAttributes, - RC LeftParen, + TokenSyntax LeftParen, FunctionParameterListSyntax ArgumentList, - RC RightParen, RC ThrowsOrRethrows, - RC Arrow, TypeSyntax ReturnType); + TokenSyntax RightParen, TokenSyntax ThrowsOrRethrows, + TokenSyntax Arrow, TypeSyntax ReturnType); /// Make a function type with all elements marked as missing. static FunctionTypeSyntax makeBlankFunctionType(); @@ -608,7 +613,7 @@ struct SyntaxFactory { /// Any elements are allowed to be marked as missing. static SameTypeRequirementSyntax makeSameTypeRequirement(TypeIdentifierSyntax LeftTypeIdentifier, - RC EqualityToken, TypeSyntax RightType); + TokenSyntax EqualityToken, TypeSyntax RightType); /// Make a list of generic requirements with the given loosely collected /// requirements/ diff --git a/include/swift/Syntax/SyntaxKinds.def b/include/swift/Syntax/SyntaxKinds.def index 5870b7091b4..a5bdfa784e5 100644 --- a/include/swift/Syntax/SyntaxKinds.def +++ b/include/swift/Syntax/SyntaxKinds.def @@ -51,12 +51,9 @@ SYNTAX_RANGE(Decl, MissingDecl, FunctionDecl) SYNTAX(DeclMembers, Syntax) SYNTAX(GenericParameter, Syntax) SYNTAX(GenericParameterClause, Syntax) -SYNTAX(GenericParameterList, Syntax) SYNTAX(GenericWhereClause, Syntax) -SYNTAX(GenericRequirementList, Syntax) SYNTAX(GenericArgumentClause, Syntax) -SYNTAX(GenericArgumentList, Syntax) ABSTRACT_SYNTAX(GenericRequirementSyntax, Syntax) SYNTAX(ConformanceRequirement, GenericRequirementSyntax) SYNTAX(SameTypeRequirement, GenericRequirementSyntax) @@ -75,7 +72,6 @@ ABSTRACT_SYNTAX(TypeSyntax, Syntax) SYNTAX_RANGE(Type, MissingType, FunctionType) // Statements -SYNTAX(StmtList, Syntax) ABSTRACT_SYNTAX(StmtSyntax, Syntax) SYNTAX(UnknownStmt, StmtSyntax) @@ -98,18 +94,22 @@ SYNTAX_RANGE(Expr, MissingExpr, SymbolicReferenceExpr) // Other stuff SYNTAX(BalancedTokens, Syntax) SYNTAX(TypeAttribute, Syntax) -SYNTAX(TypeAttributes, Syntax) SYNTAX(TupleTypeElement, Syntax) SYNTAX(FunctionTypeArgument, Syntax) -SYNTAX(FunctionCallArgumentList, Syntax) SYNTAX(FunctionCallArgument, Syntax) SYNTAX(FunctionSignature, Syntax) SYNTAX(FunctionParameter, Syntax) SYNTAX(DeclModifier, Syntax) -SYNTAX(DeclModifierList, Syntax) +SYNTAX_COLLECTION(StmtList, StmtSyntax) +SYNTAX_COLLECTION(FunctionCallArgumentList, FunctionCallArgumentSyntax) +SYNTAX_COLLECTION(DeclModifierList, DeclModifierSyntax) SYNTAX_COLLECTION(FunctionParameterList, FunctionParameterSyntax) SYNTAX_COLLECTION(TupleTypeElementList, TupleTypeElementSyntax) +SYNTAX_COLLECTION(GenericParameterList, GenericParameterSyntax) +SYNTAX_COLLECTION(GenericRequirementList, GenericRequirementSyntax) +SYNTAX_COLLECTION(GenericArgumentList, GenericArgumentSyntax) +SYNTAX_COLLECTION(TypeAttributes, TypeAttributeSyntax) #undef SYNTAX_COLLECTION #undef ABSTRACT_SYNTAX diff --git a/include/swift/Syntax/TokenKinds.def b/include/swift/Syntax/TokenKinds.def index 79c60246683..c59f6530b13 100644 --- a/include/swift/Syntax/TokenKinds.def +++ b/include/swift/Syntax/TokenKinds.def @@ -24,6 +24,8 @@ /// POUND_OLD_OBJECT_LITERAL(kw, new_kw, old_arg, new_arg) /// POUND_CONFIG(kw) /// PUNCTUATOR(name, str) +/// LITERAL(name) +/// MISC(name) /// //===----------------------------------------------------------------------===// @@ -108,6 +110,18 @@ #define PUNCTUATOR(name, str) #endif +/// LITERAL(name) +/// Tokens representing literal values, e.g. 'integer_literal'. +#ifndef LITERAL +#define LITERAL(name) +#endif + +/// MISC(name) +/// Miscellaneous tokens, e.g. 'eof' and 'unknown'. +#ifndef MISC +#define MISC(name) +#endif + // Keywords that start decls. DECL_KEYWORD(associatedtype) DECL_KEYWORD(class) @@ -253,6 +267,23 @@ POUND_KEYWORD(column) POUND_KEYWORD(function) POUND_KEYWORD(dsohandle) +// Single-token literals +LITERAL(integer_literal) +LITERAL(floating_literal) +LITERAL(string_literal) + +// Miscellaneous tokens. +MISC(unknown) +MISC(eof) +MISC(code_complete) +MISC(identifier) +MISC(oper_binary_unspaced) // "x+y" +MISC(oper_binary_spaced) // "x + y" +MISC(oper_postfix) +MISC(oper_prefix) +MISC(dollarident) +MISC(sil_local_name) // %42 in SIL mode. +MISC(comment) #undef KEYWORD #undef SWIFT_KEYWORD @@ -266,3 +297,5 @@ POUND_KEYWORD(dsohandle) #undef POUND_OLD_OBJECT_LITERAL #undef POUND_CONFIG #undef PUNCTUATOR +#undef LITERAL +#undef MISC diff --git a/include/swift/Syntax/TokenKinds.h b/include/swift/Syntax/TokenKinds.h index 08e7fd79be4..e62eab60c15 100644 --- a/include/swift/Syntax/TokenKinds.h +++ b/include/swift/Syntax/TokenKinds.h @@ -19,21 +19,8 @@ namespace swift { enum class tok { - unknown = 0, - eof, - code_complete, - identifier, - oper_binary_unspaced, // "x+y" - oper_binary_spaced, // "x + y" - oper_postfix, - oper_prefix, - dollarident, - integer_literal, - floating_literal, - string_literal, - sil_local_name, // %42 in SIL mode. - comment, - +#define LITERAL(X) X, +#define MISC(X) X, #define KEYWORD(X) kw_ ## X, #define PUNCTUATOR(X, Y) X, #define POUND_KEYWORD(X) pound_ ## X, diff --git a/include/swift/Syntax/TokenSyntax.h b/include/swift/Syntax/TokenSyntax.h index 9fe05f2959b..dca423d4fb1 100644 --- a/include/swift/Syntax/TokenSyntax.h +++ b/include/swift/Syntax/TokenSyntax.h @@ -1,4 +1,4 @@ -//===--- TokenSyntax.h - Swift Token Interface ------------------*- C++ -*-===// +//===----------- TokenSyntax.h - Swift Token Interface ----------*- C++ -*-===// // // This source file is part of the Swift.org open source project // @@ -10,191 +10,88 @@ // //===----------------------------------------------------------------------===// // -// This file contains the interface for a `TokenSyntax`, which is a token that -// includes full-fidelity leading and trailing trivia. -// -// A TokenSyntax is an instance of `RawSyntax`, meaning it is immutable, -// reference counted, and able to be shared. +// This file contains the interface for a `TokenSyntax`, which is a token +// that includes full-fidelity leading and trailing trivia. // //===----------------------------------------------------------------------===// -#ifndef SWIFT_SYNTAX_TokenSyntax_H -#define SWIFT_SYNTAX_TokenSyntax_H +#ifndef SWIFT_SYNTAX_TOKENSYNTAX_H +#define SWIFT_SYNTAX_TOKENSYNTAX_H -#include "swift/Syntax/RawSyntax.h" +#include "swift/Syntax/RawTokenSyntax.h" #include "swift/Syntax/References.h" +#include "swift/Syntax/Syntax.h" #include "swift/Syntax/TokenKinds.h" #include "swift/Syntax/Trivia.h" namespace swift { namespace syntax { -class AbsolutePosition; - -struct TokenSyntax final : public RawSyntax { - friend struct SyntaxFactory; - const tok TokenKind; - const OwnedString Text; - const Trivia LeadingTrivia; - const Trivia TrailingTrivia; - -private: - TokenSyntax(); - - TokenSyntax(tok TokenKind, OwnedString Text, const SourcePresence Presence); - - TokenSyntax(tok TokenKind, OwnedString Text, const SourcePresence Presence, - const Trivia &LeadingTrivia, const Trivia &TrailingTrivia); - +class TokenSyntax final : public Syntax { +protected: + virtual void validate() const override { + assert(getRaw()->isToken()); + } public: - /// Make a new token. - static RC make(tok TokenKind, OwnedString Text, - const SourcePresence Presence, - const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia) { - return RC { - new TokenSyntax { - TokenKind, Text, Presence, - LeadingTrivia, TrailingTrivia - } - }; + TokenSyntax(const RC Root, const SyntaxData *Data) + : Syntax(Root, Data) {} + + RC getRawToken() const { + return cast(getRaw()); } - /// Return a token with the specified kind and text, but marked as missing. - static RC missingToken(const tok Kind, OwnedString Text) { - return make(Kind, Text, SourcePresence::Missing, {}, {}); + static TokenSyntax missingToken(const tok Kind, OwnedString Text) { + return make(RawTokenSyntax::missingToken(Kind, Text)); } - /// Return a new token like this one, but with the given leading - /// trivia instead. - RC withLeadingTrivia(const Trivia &NewLeadingTrivia) const { - return make(TokenKind, Text, Presence, NewLeadingTrivia, TrailingTrivia); + const Trivia &getLeadingTrivia() const { + return getRawToken()->LeadingTrivia; } - /// Return a new token like this one, but with the given trailing - /// trivia instead. - RC withTrailingTrivia(const Trivia &NewTrailingTrivia) const { - return make(TokenKind, Text, Presence, LeadingTrivia, NewTrailingTrivia); + const Trivia &getTrailingTrivia() const { + return getRawToken()->TrailingTrivia; } - /// Returns true if the token is of the expected kind and has the given - /// expected text. - bool is(tok ExpectedKind, StringRef ExpectedText) const { - return getTokenKind() == ExpectedKind && ExpectedText == getText(); + TokenSyntax withLeadingTrivia(const Trivia &Trivia) const { + auto NewRaw = getRawToken()->withLeadingTrivia(Trivia); + return Data->replaceSelf(NewRaw); } - /// Returns the kind of token this is. - tok getTokenKind() const { return TokenKind; } + TokenSyntax withTrailingTrivia(const Trivia &Trivia) const { + auto NewRaw = getRawToken()->withTrailingTrivia(Trivia); + return Data->replaceSelf(NewRaw); + } - /// Returns a reference to the text of this token. - StringRef getText() const { return Text.str(); } - - /// True if the token is any keyword. bool isKeyword() const { - switch (TokenKind) { -#define KEYWORD(X) case tok::kw_##X: return true; -#include "swift/Syntax/TokenKinds.def" - default: return false; - } + return getRawToken()->isKeyword(); } - /// Returns true if the token is any literal. - bool isLiteral() const { - switch(TokenKind) { - case tok::integer_literal: - case tok::floating_literal: - case tok::string_literal: - case tok::pound_fileLiteral: - case tok::pound_colorLiteral: - case tok::pound_imageLiteral: - return true; - default: - return false; - } + bool isMissing() const { + return getRawToken()->isMissing(); } - /// Returns true if this token is of the specified kind. - bool is(tok K) const { return TokenKind == K; } - - /// Returns true if this token is not of the specified kind. - bool isNot(tok K) const { return TokenKind != K; } - - /// Base case for variadic `isAny` - bool isAny(tok K1) const { - return is(K1); - } - - /// Returns true if this token is any of the provided kinds. - template - bool isAny(tok K1, tok K2, T... K) const { - if (is(K1)) - return true; - return isAny(K2, K...); - } - - /// Returns true if this token is not any of the provided kinds. - template - bool isNot(tok K1, T... K) const { return !isAny(K1, K...); } - bool isPunctuation() const { - switch (TokenKind) { -#define PUNCTUATOR(Name, Str) case tok::Name: return true; -#include "swift/Syntax/TokenKinds.def" - default: return false; - } + return getRawToken()->isPunctuation(); } - /// Returns true if this token is a binary operator. - bool isBinaryOperator() const { - return TokenKind == tok::oper_binary_spaced || - TokenKind == tok::oper_binary_unspaced; - } - - /// Returns true if this token is any kind of operator. bool isOperator() const { - return isBinaryOperator() || - TokenKind == tok::oper_postfix || - TokenKind == tok::oper_prefix; + return getRawToken()->isOperator(); } - /// Returns true if this token is not an operator. - bool isNotOperator() const { - return !isOperator(); + bool isLiteral() const { + return getRawToken()->isLiteral(); } - /// Print the leading trivia, text, and trailing trivia of this token to - /// the provided output stream. - void print(llvm::raw_ostream &OS, unsigned Indent = 0) const { - for (const auto &Leader : LeadingTrivia) { - Leader.print(OS); - } - - if (!isMissing()) { - OS << getText(); - } - - for (const auto &Trailer : TrailingTrivia) { - Trailer.print(OS); - } + tok getTokenKind() const { + return getRawToken()->getTokenKind(); } - /// Advance the provided AbsolutePosition by the token's full width and - /// return the AbsolutePosition of the start of the token's nontrivial text. - AbsolutePosition accumulateAbsolutePosition(AbsolutePosition &Pos) const; - - /// Dump the textual representation of this token's kind. - void dumpKind(llvm::raw_ostream &OS) const; - - /// Dump the layout of this token: its leading trivia, kind, text, and - /// trailing trivia. - void dump(llvm::raw_ostream &OS, unsigned Indent = 0) const; - - static bool classof(const RawSyntax *RS) { - return RS->Kind == SyntaxKind::Token; + StringRef getText() const { + return getRawToken()->getText(); } }; } // end namespace syntax } // end namespace swift -#endif // SWIFT_SYNTAX_TokenSyntax_H +#endif // SWIFT_SYNTAX_TOKENSYNTAX_H diff --git a/include/swift/Syntax/TypeSyntax.h b/include/swift/Syntax/TypeSyntax.h index 9679e7c3cf5..e77d2930b95 100644 --- a/include/swift/Syntax/TypeSyntax.h +++ b/include/swift/Syntax/TypeSyntax.h @@ -28,28 +28,7 @@ namespace swift { namespace syntax { class GenericArgumentClauseSyntax; -class GenericArgumentClauseSyntaxData; class GenericParameterClauseSyntax; -class GenericParameterClauseSyntaxData; - -#pragma mark - balanced-tokens Data - -class BalancedTokensSyntaxData final : public SyntaxData { - friend class SyntaxData; - friend struct SyntaxFactory; - - BalancedTokensSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::BalancedTokens; - } -}; #pragma mark - balanced-tokens API @@ -57,56 +36,31 @@ public: /// | Any punctuation except (, ), [, ], {, or } class BalancedTokensSyntax final : public Syntax { friend struct SyntaxFactory; - friend class SyntaxData; - - using DataType = BalancedTokensSyntaxData; - - BalancedTokensSyntax(RC Root, - const BalancedTokensSyntaxData *Data); + + virtual void validate() const override; public: + static BalancedTokensSyntax makeBlank(); + BalancedTokensSyntax(const RC Root, const SyntaxData *Data) + : Syntax(Root, Data) {} + // TODO: TODO: BalancedTokensSyntax::getBalancedToken BalancedTokensSyntax - addBalancedToken(RC NewBalancedToken) const; + addBalancedToken(TokenSyntax NewBalancedToken) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::BalancedTokens; } }; -#pragma mark - type-attribute Data - -class TypeAttributeSyntaxData final : public SyntaxData { - friend class SyntaxData; - RC CachedBalancedTokens; - friend struct SyntaxFactory; - - TypeAttributeSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); - -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::TypeAttribute; - } -}; - #pragma mark - type-attribute API /// type-attribute -> '@' identifier attribute-argument-clause? /// attribute-argument-clause -> '(' balanced-tokens ')' class TypeAttributeSyntax final : public Syntax { friend struct SyntaxFactory; - friend class TypeAttributeSyntaxData; - friend class SyntaxData; - - using DataType = TypeAttributeSyntaxData; - + enum class Cursor : CursorIndex { AtSignToken, Identifier, @@ -115,28 +69,31 @@ class TypeAttributeSyntax final : public Syntax { RightParenToken, }; - TypeAttributeSyntax(RC Root, const TypeAttributeSyntaxData *Data); + virtual void validate() const override; public: + static TypeAttributeSyntax makeBlank(); + TypeAttributeSyntax(const RC Root, const SyntaxData *Data) + : Syntax(Root, Data) {} /// Return the '@' token associated with the type attribute. - RC getAtSignToken() const; + TokenSyntax getAtSignToken() const; /// Return a new TypeAttributeSyntax with the given '@' token. - TypeAttributeSyntax withAtSignToken(RC NewAtSignToken) const; + TypeAttributeSyntax withAtSignToken(TokenSyntax NewAtSignToken) const; /// Return the name of the type attribute. - RC getIdentifier() const; + TokenSyntax getIdentifier() const; /// Return a new TypeAttributeSyntax with the given name. - TypeAttributeSyntax withIdentifier(RC NewIdentifier) const; + TypeAttributeSyntax withIdentifier(TokenSyntax NewIdentifier) const; /// Return the left parenthesis '(' token attached to the type attribute. - RC getLeftParenToken() const; + TokenSyntax getLeftParenToken() const; /// Return a TypeAttributeSyntax with the given left parenthesis '(' token. TypeAttributeSyntax - withLeftParenToken(RC NewLeftParenToken) const; + withLeftParenToken(TokenSyntax NewLeftParenToken) const; /// Return the "balanced tokens" of the type attributes; the arguments. BalancedTokensSyntax getBalancedTokens() const; @@ -147,81 +104,17 @@ public: withBalancedTokens(BalancedTokensSyntax NewBalancedTokens) const; /// Return the right parenthesis ')' token attached to the type attribute. - RC getRightParenToken() const; + TokenSyntax getRightParenToken() const; /// Return a TypeAttributeSyntax with the given right parenthesis ')' token. TypeAttributeSyntax - withRightParenToken(RC NewRightParenToken) const; + withRightParenToken(TokenSyntax NewRightParenToken) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::TypeAttribute; } }; -#pragma mark - type-attributes Data - -class TypeAttributesSyntaxData final : public SyntaxData { - friend class SyntaxData; - friend class TypeAttributesSyntax; - friend struct SyntaxFactory; - - TypeAttributesSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::TypeAttributes; - } -}; - -#pragma mark - type-attributes API - -/// type-attributes -> type-attribute -/// | type-attribute type-attributes -class TypeAttributesSyntax final : public Syntax { - friend struct SyntaxFactory; - friend class TypeAttributesSyntaxData; - friend class SyntaxData; - friend class FunctionSignatureSyntax; - friend class FunctionDeclSyntax; - - using DataType = TypeAttributesSyntaxData; - - TypeAttributesSyntax(RC Root, - const TypeAttributesSyntaxData *Data); -public: - // TODO: Convert to SyntaxCollection - // - - TypeAttributesSyntax - addTypeAttribute(TypeAttributeSyntax NewTypeAttribute) const; - - static bool classof(const Syntax *S) { - return S->getKind() == SyntaxKind::TypeAttributes; - } -}; - -#pragma mark - type-syntax Data - -class TypeSyntaxData : public SyntaxData { - friend class SyntaxData; - friend class TypeSyntax; - -protected: - TypeSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - -public: - static bool classof(const SyntaxData *S) { - return S->isType(); - } -}; - #pragma mark - type-syntax API /// type -> array-type @@ -236,53 +129,27 @@ public: /// | 'Any' /// | 'Self' class TypeSyntax : public Syntax { - using DataType = TypeSyntaxData; - friend class SyntaxData; friend class FunctionParameterSyntax; friend class FunctionSignatureSyntax; protected: - TypeSyntax(const RC Root, const TypeSyntaxData *Data); + virtual void validate() const override {} + public: + static TypeSyntax makeBlank(); + TypeSyntax(const RC Root, const SyntaxData *Data) + : Syntax(Root, Data) {} static bool classof(const Syntax *S) { return S->isType(); } }; -#pragma mark - type-identifier Data - -class TypeIdentifierSyntaxData final : public TypeSyntaxData { - friend struct SyntaxFactory; - friend class TypeIdentifierSyntax; - friend class SyntaxData; - - RC CachedGenericArgumentClause; - RC CachedChildTypeIdentifier; - - TypeIdentifierSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - - static RC make (RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::TypeIdentifier; - } -}; - #pragma mark - type-identifier API /// type-identifier -> type-name generic-argument-clause? /// | type-name generic-argument-clause '.' type-identifier class TypeIdentifierSyntax final : public TypeSyntax { friend struct SyntaxFactory; - friend class TypeIdentifierSyntaxData; - friend class SyntaxData; - - using DataType = TypeIdentifierSyntaxData; - + private: enum class Cursor { Identifier, @@ -291,21 +158,24 @@ private: ChildTypeIdentifier, }; - TypeIdentifierSyntax(RC Root, - const TypeIdentifierSyntaxData *Data); + virtual void validate() const override; public: - RC getIdentifier() const; + static TypeIdentifierSyntax makeBlank(); + TypeIdentifierSyntax(const RC Root, const SyntaxData *Data) + : TypeSyntax(Root, Data) {} + + TokenSyntax getIdentifier() const; TypeIdentifierSyntax - withIdentifier(RC NewIdentifier) const; + withIdentifier(TokenSyntax NewIdentifier) const; GenericArgumentClauseSyntax getGenericArgumentClause() const; TypeIdentifierSyntax withGenericArgumentClause(GenericArgumentClauseSyntax NewGenericArgs) const; - RC getDotToken() const; - TypeIdentifierSyntax withDotToken(RC NewIdentifier) const; + TokenSyntax getDotToken() const; + TypeIdentifierSyntax withDotToken(TokenSyntax NewIdentifier) const; TypeIdentifierSyntax getChildType() const; TypeIdentifierSyntax addChildType(TypeIdentifierSyntax ChildType) const; @@ -315,25 +185,6 @@ public: } }; -#pragma mark - tuple-type-element Data - -class TupleTypeElementSyntaxData final : public SyntaxData { - friend class SyntaxData; - friend struct SyntaxFactory; - - TupleTypeElementSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::TupleTypeElement; - } -}; - #pragma mark - tuple-type-element API /// tuple-type-element -> (identifier ':')? type-attributes? 'inout'? type @@ -342,9 +193,7 @@ public: /// a type without a label. class TupleTypeElementSyntax final : public Syntax { friend struct SyntaxFactory; - friend class TupleTypeElementSyntaxData; - friend class SyntaxData; - + enum class Cursor : CursorIndex { Label, ColonToken, @@ -354,32 +203,34 @@ class TupleTypeElementSyntax final : public Syntax { CommaToken, }; - TupleTypeElementSyntax(RC Root, - const TupleTypeElementSyntaxData *Data); + virtual void validate() const override; + public: - using DataType = TupleTypeElementSyntaxData; + static TupleTypeElementSyntax makeBlank(); + TupleTypeElementSyntax(const RC Root, const SyntaxData *Data) + : Syntax(Root, Data) {} /// Return the label of the tuple type element. - RC getLabel() const; + TokenSyntax getLabel() const; /// Return a new named tuple type element with the specified identifier. - TupleTypeElementSyntax withLabel(RC NewIdentifier) const; + TupleTypeElementSyntax withLabel(TokenSyntax NewIdentifier) const; /// Return the colon token of the tuple type element. - RC getColonToken() const; + TokenSyntax getColonToken() const; /// Return a new named tuple type element with a colon token replacement /// using the specified leading and trailing trivia. TupleTypeElementSyntax - withColonToken(RC NewColonToken) const; + withColonToken(TokenSyntax NewColonToken) const; /// Return the comma token of the tuple type element. - RC getCommaToken() const; + TokenSyntax getCommaToken() const; /// Return a new named tuple type element with a comma token replacement /// using the specified leading and trailing trivia. TupleTypeElementSyntax - withCommaToken(RC NewCommaToken) const; + withCommaToken(TokenSyntax NewCommaToken) const; /// Return the type attributes for the tuple type element. TypeAttributesSyntax getTypeAttributes() const; @@ -389,10 +240,10 @@ public: withTypeAttributes(TypeAttributesSyntax NewTypeAttributes) const; /// Return the 'inout' token of the tuple type element. - RC getInoutToken() const; + TokenSyntax getInoutToken() const; /// Return a new named tuple type element with the 'inout' keyword added. - TupleTypeElementSyntax withInoutToken(RC NewInoutToken) const; + TupleTypeElementSyntax withInoutToken(TokenSyntax NewInoutToken) const; TypeSyntax getTypeSyntax() const; @@ -404,55 +255,29 @@ public: } }; -#pragma mark - tuple-type-element-list API - -using TupleTypeElementListSyntax = - SyntaxCollection; - -#pragma mark - tuple-type Data - -class TupleTypeSyntaxData final : public TypeSyntaxData { - friend class SyntaxData; - friend struct SyntaxFactory; - friend class TupleTypeSyntaxBuilder; - TupleTypeSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); - -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::TupleType; - } -}; - #pragma mark - tuple-type API /// tuple-type -> '(' tuple-type-element-list ')' class TupleTypeSyntax final : public TypeSyntax { friend struct SyntaxFactory; - friend class TupleTypeSyntaxData; - friend class SyntaxData; friend class TupleTypeSyntaxBuilder; - using DataType = TupleTypeSyntaxData; - enum class Cursor : CursorIndex { LeftParenToken, TypeElementList, RightParenToken, }; - TupleTypeSyntax(RC Root, const TupleTypeSyntaxData *Data); + virtual void validate() const override; public: + static TupleTypeSyntax makeBlank(); + TupleTypeSyntax(const RC Root, const SyntaxData *Data) + : TypeSyntax(Root, Data) {} + /// Return the left paren '(' token surrounding the tuple type syntax. - RC getLeftParen() const; - TupleTypeSyntax withLeftParen(RC NewLeftParen) const; + TokenSyntax getLeftParen() const; + TupleTypeSyntax withLeftParen(TokenSyntax NewLeftParen) const; /// Get the type argument list inside the tuple type syntax. TupleTypeElementListSyntax getTypeElementList() const; @@ -462,8 +287,8 @@ public: withTypeElementList(TupleTypeElementListSyntax NewTypeElementList) const; /// Return the right paren ')' token surrounding the tuple type syntax. - RC getRightParen() const; - TupleTypeSyntax withRightParen(RC NewRightParen) const; + TokenSyntax getRightParen() const; + TupleTypeSyntax withRightParen(TokenSyntax NewRightParen) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::TupleType; @@ -482,14 +307,14 @@ public: TupleTypeSyntaxBuilder(); /// Use the given left paren '(' token when building the tuple type syntax. - TupleTypeSyntaxBuilder &useLeftParen(RC LeftParen); + TupleTypeSyntaxBuilder &useLeftParen(TokenSyntax LeftParen); /// Add an element type to the eventual tuple type syntax. TupleTypeSyntaxBuilder & addElementTypeSyntax(TupleTypeElementSyntax ElementTypeSyntax); /// Use the given left paren '(' token when building the tuple type syntax. - TupleTypeSyntaxBuilder &useRightParen(RC RightParen); + TupleTypeSyntaxBuilder &useRightParen(TokenSyntax RightParen); /// Build a TupleTypeSyntax from the elements seen so far. /// @@ -498,102 +323,65 @@ public: TupleTypeSyntax build() const; }; -#pragma mark - metatype-type Data - -class MetatypeTypeSyntaxData final : public TypeSyntaxData { - friend struct SyntaxFactory; - friend class SyntaxData; - MetatypeTypeSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::MetatypeType; - } -}; - #pragma mark - metatype-type API /// metatype-type -> type '.' 'Type' /// | type '.' 'Protocol' class MetatypeTypeSyntax final : public TypeSyntax { friend struct SyntaxFactory; - friend class MetatypeTypeSyntaxData; - friend class SyntaxData; - - using DataType = MetatypeTypeSyntaxData; - + enum class Cursor : CursorIndex { BaseType, DotToken, TypeToken, }; - MetatypeTypeSyntax(RC Root, const MetatypeTypeSyntaxData *Data); + virtual void validate() const override; public: + static MetatypeTypeSyntax makeBlank(); + MetatypeTypeSyntax(const RC Root, const SyntaxData *Data) + : TypeSyntax(Root, Data) {} + TypeSyntax getBaseTypeSyntax() const; /// Return a new metatype type with the given base type - the `A` in `A.Type`. MetatypeTypeSyntax withBaseTypeSyntax(TypeSyntax NewBaseType) const; /// Return the dot token. - RC getDotToken() const; + TokenSyntax getDotToken() const; /// Return a new metatype type with the given dot token. - MetatypeTypeSyntax withDotToken(RC NewDotToken) const; + MetatypeTypeSyntax withDotToken(TokenSyntax NewDotToken) const; /// Return the child type - either the identifiers `Type` or `Protocol`. - RC getTypeToken() const; + TokenSyntax getTypeToken() const; /// Return a new metatype type with the given child type - either the /// identifiers: `Type` or `Protocol`. - MetatypeTypeSyntax withTypeToken(RC NewTypeToken) const; + MetatypeTypeSyntax withTypeToken(TokenSyntax NewTypeToken) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::MetatypeType; } }; -#pragma mark - optional-type Data - -class OptionalTypeSyntaxData final : public TypeSyntaxData { - friend class SyntaxData; - friend struct SyntaxFactory; - OptionalTypeSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::OptionalType; - } -}; - #pragma mark - optional-type API /// optional-type -> type '?' class OptionalTypeSyntax final : public TypeSyntax { friend struct SyntaxFactory; - friend class OptionalTypeSyntaxData; - friend class SyntaxData; - - using DataType = OptionalTypeSyntaxData; - + enum class Cursor : CursorIndex { BaseType, QuestionToken }; - OptionalTypeSyntax(RC Root, const OptionalTypeSyntaxData *Data); - + virtual void validate() const override; public: + static OptionalTypeSyntax makeBlank(); + OptionalTypeSyntax(const RC Root, const SyntaxData *Data) + : TypeSyntax(Root, Data) {} + /// Return the syntax of the type to which this optional type refers. TypeSyntax getBaseTypeSyntax() const; @@ -601,53 +389,33 @@ public: OptionalTypeSyntax withBaseTypeSyntax(TypeSyntax NewBaseType) const; /// Return the question-mark '?' token attached to this optional type syntax. - RC getQuestionToken() const; + TokenSyntax getQuestionToken() const; /// Return a new optional type with the given question-mark token. OptionalTypeSyntax - withQuestionToken(RC NewQuestionToken) const; + withQuestionToken(TokenSyntax NewQuestionToken) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::OptionalType; } }; -#pragma mark - implicitly-unwrapped-optional-type Data - -class ImplicitlyUnwrappedOptionalTypeSyntaxData final : public TypeSyntaxData { - friend struct SyntaxFactory; - friend class SyntaxData; - ImplicitlyUnwrappedOptionalTypeSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - - static RC - make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::ImplicitlyUnwrappedOptionalType; - } -}; - #pragma mark - implicitly-unwrapped-optional-type API /// implicitly-unwrapped-optional-type -> type '!' class ImplicitlyUnwrappedOptionalTypeSyntax final : public TypeSyntax { friend struct SyntaxFactory; - friend class ImplicitlyUnwrappedOptionalTypeSyntaxData; - friend class SyntaxData; - - using DataType = ImplicitlyUnwrappedOptionalTypeSyntaxData; - + enum class Cursor : CursorIndex { Type, ExclaimToken }; - ImplicitlyUnwrappedOptionalTypeSyntax(RC Root, - const ImplicitlyUnwrappedOptionalTypeSyntaxData *Data); + virtual void validate() const override; public: + static ImplicitlyUnwrappedOptionalTypeSyntax makeBlank(); + ImplicitlyUnwrappedOptionalTypeSyntax(const RC Root, + const SyntaxData *Data) + : TypeSyntax(Root, Data) {} + /// Return the syntax for the base type to which this implicitly unwrapped /// optional type refers. TypeSyntax getBaseTypeSyntax() const; @@ -659,116 +427,67 @@ public: /// Return the exclamation-mark '!' token attached to the end of this /// implicitly unwrapped optional type syntax. - RC getExclaimToken() const; + TokenSyntax getExclaimToken() const; /// Return a new implicitly unwrapped optional type with the given /// exclamation-mark '!' token. ImplicitlyUnwrappedOptionalTypeSyntax - withExclaimToken(RC NewExclaimToken) const; + withExclaimToken(TokenSyntax NewExclaimToken) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::OptionalType; } }; -#pragma mark - array-type Data - -class ArrayTypeSyntaxData final : public TypeSyntaxData { - friend class SyntaxData; - friend struct SyntaxFactory; - - ArrayTypeSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); - -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::OptionalType; - } -}; - #pragma mark - array-type API // array-type -> '[' type ']' class ArrayTypeSyntax final : public TypeSyntax { friend struct SyntaxFactory; - friend class ArrayTypeSyntaxData; - friend class SyntaxData; - - using DataType = ArrayTypeSyntaxData; - + enum class Cursor : CursorIndex { LeftSquareBracketToken, Type, RightSquareBracketToken, }; - ArrayTypeSyntax(RC Root, const ArrayTypeSyntaxData *Data); - + virtual void validate() const override; public: + static ArrayTypeSyntax makeBlank(); + + ArrayTypeSyntax(const RC Root, const SyntaxData *Data) + : TypeSyntax(Root, Data) {} + /// Return the left square bracket '[' token surrounding the array /// type syntax. - RC getLeftSquareBracketToken() const; + TokenSyntax getLeftSquareBracketToken() const; /// Return a new array type with the given left square bracket token. ArrayTypeSyntax - withLeftSquareBracketToken(RC NewLeftSquareBracketToken) const; + withLeftSquareBracketToken(TokenSyntax NewLeftSquareBracketToken) const; /// Return a new array type with the given element type. ArrayTypeSyntax withType(TypeSyntax NewType) const; /// Return the right square bracket ']' token surrounding the array /// type syntax. - RC getRightSquareBracketToken() const; + TokenSyntax getRightSquareBracketToken() const; /// Return a new array type with the given right square bracket token. ArrayTypeSyntax - withRightSquareBracketToken(RC NewRightSquareBracketToken) const; + withRightSquareBracketToken(TokenSyntax NewRightSquareBracketToken) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::ArrayType; } }; -#pragma mark - dictionary-type Data - -class DictionaryTypeSyntaxData final : public TypeSyntaxData { - friend class SyntaxData; - friend class DictionaryTypeSyntax; - friend struct SyntaxFactory; - - RC CachedKeyTypeSyntax; - RC CachedValueTypeSyntax; - - DictionaryTypeSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::ArrayType; - } -}; - #pragma mark - dictionary-type API // dictionary-type -> '[' type ':' type ']' class DictionaryTypeSyntax final : public TypeSyntax { friend struct SyntaxFactory; - friend class DictionaryTypeSyntaxData; - friend class SyntaxData; - - using DataType = DictionaryTypeSyntaxData; - + enum class Cursor : CursorIndex { LeftSquareBracketToken, KeyType, @@ -777,17 +496,21 @@ class DictionaryTypeSyntax final : public TypeSyntax { RightSquareBracketToken, }; - DictionaryTypeSyntax(RC Root, - const DictionaryTypeSyntaxData *Data); + virtual void validate() const override; public: + static DictionaryTypeSyntax makeBlank(); + + DictionaryTypeSyntax(const RC Root, const SyntaxData *Data) + : TypeSyntax(Root, Data) {} + /// Return the left square bracket '[' token surrounding the dictionary /// type syntax. - RC getLeftSquareBracketToken() const; + TokenSyntax getLeftSquareBracketToken() const; /// Return a new dictionary type with the given left square bracket token. DictionaryTypeSyntax - withLeftSquareBracketToken(RC NewLeftSquareBracketToken) const; + withLeftSquareBracketToken(TokenSyntax NewLeftSquareBracketToken) const; /// Return the key type syntax for this dictionary type. TypeSyntax getKeyTypeSyntax() const; @@ -796,10 +519,10 @@ public: DictionaryTypeSyntax withKeyTypeSyntax(TypeSyntax NewKeyType) const; /// Get the colon token in the dictionary type syntax. - RC getColonToken() const; + TokenSyntax getColonToken() const; /// Return a new dictionary type with the given colon token. - DictionaryTypeSyntax withColon(RC NewColonToken) const; + DictionaryTypeSyntax withColon(TokenSyntax NewColonToken) const; /// Return the value type syntax for this dictionary type. TypeSyntax getValueTypeSyntax() const; @@ -809,46 +532,22 @@ public: /// Return the right square bracket ']' token surrounding the dictionary /// type syntax. - RC getRightSquareBracketToken() const; + TokenSyntax getRightSquareBracketToken() const; /// Return a new dictionary type with the given right square bracket token. DictionaryTypeSyntax - withRightSquareBracketToken(RC NewRightSquareBracketToken) const; + withRightSquareBracketToken(TokenSyntax NewRightSquareBracketToken) const; static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::DictionaryType; } }; -#pragma mark - function-type-argument Data - -class FunctionTypeArgumentSyntaxData final : public SyntaxData { - friend class SyntaxData; - friend struct SyntaxFactory; - - FunctionTypeArgumentSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - - static RC - make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); -public: - static bool classof(const SyntaxData *SD) { - return SD->getKind() == SyntaxKind::FunctionTypeArgument; - } -}; - #pragma mark - function-type-argument API class FunctionTypeArgumentSyntax final : public Syntax { friend struct SyntaxFactory; - friend class SyntaxData; - - using DataType = FunctionTypeArgumentSyntaxData; - + enum class Cursor : CursorIndex { ExternalParameterName, LocalParameterName, @@ -858,37 +557,18 @@ class FunctionTypeArgumentSyntax final : public Syntax { Type, }; - FunctionTypeArgumentSyntax(RC Root, - const FunctionTypeArgumentSyntaxData *Data); + virtual void validate() const override; public: + static FunctionTypeArgumentSyntax makeBlank(); + FunctionTypeArgumentSyntax(const RC Root, const SyntaxData *Data) + : Syntax(Root, Data) {} + static bool classof(const Syntax *S) { return S->getKind() == SyntaxKind::FunctionTypeArgument; } }; - -#pragma mark - function-type Data - -class FunctionTypeSyntaxData final : public TypeSyntaxData { - friend class SyntaxData; - friend class FunctionTypeSyntax; - friend class FunctionTypeSyntaxBuilder; - friend struct SyntaxFactory; - - FunctionTypeSyntaxData(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - static RC makeBlank(); -public: - static bool classof(const SyntaxData *S) { - return S->getKind() == SyntaxKind::DictionaryType; - } -}; - #pragma mark - function-type API /// function-type -> @@ -897,11 +577,7 @@ public: class FunctionTypeSyntax final : public TypeSyntax { friend struct SyntaxFactory; friend class FunctionTypeSyntaxBuilder; - friend class FunctionTypeSyntaxData; - friend class SyntaxData; - - using DataType = FunctionTypeSyntaxData; - + enum class Cursor : CursorIndex { TypeAttributes, LeftParen, @@ -912,10 +588,11 @@ class FunctionTypeSyntax final : public TypeSyntax { ReturnType }; - FunctionTypeSyntax(RC Root, - const FunctionTypeSyntaxData *Data); - + virtual void validate() const override; public: + static FunctionTypeSyntax makeBlank(); + FunctionTypeSyntax(const RC Root, const SyntaxData *Data) + : TypeSyntax(Root, Data) {} /// Return the type attributes for the function type. TypeAttributesSyntax getAttributes() const; @@ -925,17 +602,17 @@ public: withTypeAttributes(TypeAttributesSyntax NewAttributes) const; /// Return the left parenthesis '(' token surrounding the argument type. - RC getLeftArgumentsParen() const; + TokenSyntax getLeftArgumentsParen() const; /// Return a new function type with the given left parenthesis on the type /// argument list. FunctionTypeSyntax - withLeftArgumentsParen(RC NewLeftParen) const; + withLeftArgumentsParen(TokenSyntax NewLeftParen) const; /// Return a new function type with the additional argument type and /// optionally a preceding comma token. FunctionTypeSyntax - addTypeArgument(llvm::Optional> MaybeComma, + addTypeArgument(llvm::Optional MaybeComma, FunctionTypeArgumentSyntax NewArgument) const; /// Return the type arguments list for this function type syntax. @@ -948,32 +625,32 @@ public: withTypeElementList(TupleTypeElementListSyntax NewArgumentList) const; /// Return the right parenthesis ')' token surrounding the argument type. - RC getRightArgumentsParen() const; + TokenSyntax getRightArgumentsParen() const; /// Return a new function type with the given right parenthesis ')' /// on the type argument list. FunctionTypeSyntax - withRightArgumentsParen(RC NewRightParen) const; + withRightArgumentsParen(TokenSyntax NewRightParen) const; /// Return the 'throws' or 'rethrows' keyword on the function type syntax. - RC getThrowsOrRethrowsKeyword() const; + TokenSyntax getThrowsOrRethrowsKeyword() const; /// Return a new function type with the given `throws` keyword. /// /// This fills the same slot held by the `rethrows` keyword. - FunctionTypeSyntax withThrowsKeyword(RC NewThrowsKeyword) const; + FunctionTypeSyntax withThrowsKeyword(TokenSyntax NewThrowsKeyword) const; /// Return a new function type with the given `rethrows` keyword. /// /// This fills the same slot held by the `throws` keyword. FunctionTypeSyntax - withRethrowsKeyword(RC NewThrowsKeyword) const; + withRethrowsKeyword(TokenSyntax NewThrowsKeyword) const; /// Return the arrow token in the function type syntax. - RC getArrow() const; + TokenSyntax getArrow() const; /// Return a new function type with the given arrow token. - FunctionTypeSyntax withArrow(RC NewArrow) const; + FunctionTypeSyntax withArrow(TokenSyntax NewArrow) const; // Return the return type syntax for the function type. TypeSyntax getReturnTypeSyntax() const; @@ -1000,22 +677,22 @@ public: useTypeAttributes(TypeAttributeSyntax NewAttributes); /// Use the given left paren '(' token on the argument type syntax. - FunctionTypeSyntaxBuilder &useLeftArgumentsParen(RC LeftParen); + FunctionTypeSyntaxBuilder &useLeftArgumentsParen(TokenSyntax LeftParen); FunctionTypeSyntaxBuilder & - addArgumentTypeSyntax(llvm::Optional> MaybeComma, + addArgumentTypeSyntax(llvm::Optional MaybeComma, FunctionTypeArgumentSyntax Argument); /// Use the given right paren ')' token on the argument type syntax. - FunctionTypeSyntaxBuilder &useRightArgumentsParen(RC RightParen); + FunctionTypeSyntaxBuilder &useRightArgumentsParen(TokenSyntax RightParen); /// Use the given 'throws' keyword in the function type syntax. - FunctionTypeSyntaxBuilder &useThrowsKeyword(RC ThrowsKeyword); + FunctionTypeSyntaxBuilder &useThrowsKeyword(TokenSyntax ThrowsKeyword); FunctionTypeSyntaxBuilder & - useRethrowsKeyword(RC RethrowsKeyword); + useRethrowsKeyword(TokenSyntax RethrowsKeyword); - FunctionTypeSyntaxBuilder &useArrow(RC Arrow); + FunctionTypeSyntaxBuilder &useArrow(TokenSyntax Arrow); FunctionTypeSyntaxBuilder &useReturnTypeSyntax(TypeSyntax ReturnType); FunctionTypeSyntax build() const; diff --git a/include/swift/Syntax/UnknownSyntax.h b/include/swift/Syntax/UnknownSyntax.h index 39d265b09ef..5b390efa159 100644 --- a/include/swift/Syntax/UnknownSyntax.h +++ b/include/swift/Syntax/UnknownSyntax.h @@ -21,40 +21,6 @@ namespace swift { namespace syntax { -#pragma mark unknown-syntax Data - -class UnknownSyntaxData : public SyntaxData { - friend class SyntaxData; - friend class UnknownSyntax; - friend struct SyntaxFactory; - friend class LegacyASTTransformer; - -protected: - std::vector> CachedChildren; - - UnknownSyntaxData(const RC Raw, - const SyntaxData *Parent = nullptr, - const CursorIndex IndexInParent = 0); -public: - - static RC make(RC Raw, - const SyntaxData *Parent = nullptr, - CursorIndex IndexInParent = 0); - - size_t getNumChildren() const { - return CachedChildren.size(); - } - - /// Get the child at the given Index. - /// - /// Precondition: Index <= getNumChildren(); - Syntax getChild(size_t Index) const; - - static bool classof(const SyntaxData *SD) { - return SD->isUnknown(); - } -}; - #pragma mark unknown-syntax API /// A chunk of "unknown" syntax. @@ -66,10 +32,10 @@ class UnknownSyntax : public Syntax { friend struct SyntaxFactory; friend class Syntax; - using DataType = UnknownSyntaxData; - + virtual void validate() const override; public: - UnknownSyntax(const RC Root, const UnknownSyntaxData *Data); + UnknownSyntax(const RC Root, const SyntaxData *Data) + : Syntax(Root, Data) {} /// Get the number of child nodes in this piece of syntax, not including /// tokens. diff --git a/include/swift/TBDGen/TBDGen.h b/include/swift/TBDGen/TBDGen.h index 3d6b36a51a7..9dfa041a2be 100644 --- a/include/swift/TBDGen/TBDGen.h +++ b/include/swift/TBDGen/TBDGen.h @@ -18,7 +18,8 @@ namespace swift { class FileUnit; void enumeratePublicSymbols(FileUnit *module, llvm::StringSet<> &symbols, - bool hasMultipleIRGenThreads, bool isWholeModule); + bool hasMultipleIRGenThreads, bool isWholeModule, + bool silSerializeWitnessTables); } // end namespace swift #endif diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 93cdbcdb03f..861e40f146a 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -2664,7 +2664,8 @@ BuiltinVectorType *BuiltinVectorType::get(const ASTContext &context, } ParenType *ParenType::get(const ASTContext &C, Type underlying, - ParameterTypeFlags flags) { + ParameterTypeFlags fl) { + auto flags = fl.withInOut(underlying->is()); auto properties = underlying->getRecursiveProperties(); auto arena = getArena(properties); ParenType *&Result = @@ -2737,6 +2738,14 @@ Type TupleType::get(ArrayRef Fields, const ASTContext &C) { return New; } +TupleTypeElt::TupleTypeElt(Type ty, Identifier name, + ParameterTypeFlags fl) +: Name(name), ElementType(ty), Flags(fl.withInOut(ty->is())) { + // FIXME: Re-enable this assertion and hunt down the callers that aren't + // setting parameter bits correctly. + // assert((ty->is() && fl.isInOut()) && "caller did not set flags"); +} + void UnboundGenericType::Profile(llvm::FoldingSetNodeID &ID, GenericTypeDecl *TheDecl, Type Parent) { ID.AddPointer(TheDecl); @@ -3130,6 +3139,17 @@ getGenericFunctionRecursiveProperties(Type Input, Type Result) { return properties; } +ArrayRef AnyFunctionType::getParams() const { + switch (getKind()) { + case TypeKind::Function: + return cast(this)->getParams(); + case TypeKind::GenericFunction: + return cast(this)->getParams(); + default: + llvm_unreachable("Undefined function type"); + } +} + AnyFunctionType *AnyFunctionType::withExtInfo(ExtInfo info) const { if (isa(this)) return FunctionType::get(getInput(), getResult(), info); @@ -3144,32 +3164,88 @@ AnyFunctionType *AnyFunctionType::withExtInfo(ExtInfo info) const { llvm_unreachable("unhandled function type"); } -FunctionType *FunctionType::get(Type Input, Type Result, - const ExtInfo &Info) { - auto properties = getFunctionRecursiveProperties(Input, Result); - auto arena = getArena(properties); - uint16_t attrKey = Info.getFuncAttrKey(); +void AnyFunctionType::decomposeInput( + Type type, SmallVectorImpl &result) { + switch (type->getKind()) { + case TypeKind::Tuple: { + auto tupleTy = cast(type.getPointer()); + for (auto &elt : tupleTy->getElements()) { + result.push_back(AnyFunctionType::Param(elt)); + } + return; + } + + case TypeKind::Paren: { + auto ty = cast(type.getPointer())->getUnderlyingType(); + result.push_back(AnyFunctionType::Param(ty)); + return; + } + + default: + result.push_back(AnyFunctionType::Param(type)); + return; + } +} - const ASTContext &C = Input->getASTContext(); +Type AnyFunctionType::composeInput(ASTContext &ctx, ArrayRef params, + bool canonicalVararg) { + SmallVector elements; + for (const auto ¶m : params) { + Type eltType = param.getType(); + if (param.isVariadic()) { + if (canonicalVararg) + eltType = BoundGenericType::get(ctx.getArrayDecl(), Type(), {eltType}); + else + eltType = ArraySliceType::get(eltType); + } + elements.push_back(TupleTypeElt(eltType, param.getLabel(), + param.getParameterFlags())); + } + return TupleType::get(elements, ctx); +} + +FunctionType *FunctionType::get(ArrayRef params, + Type result, const ExtInfo &info, + bool canonicalVararg) { + return get(composeInput(result->getASTContext(), params, canonicalVararg), + result, info); +} + +FunctionType *FunctionType::get(Type input, Type result, + const ExtInfo &info) { + auto properties = getFunctionRecursiveProperties(input, result); + auto arena = getArena(properties); + uint16_t attrKey = info.getFuncAttrKey(); + + const ASTContext &C = input->getASTContext(); FunctionType *&Entry - = C.Impl.getArena(arena).FunctionTypes[{Input, {Result, attrKey} }]; + = C.Impl.getArena(arena).FunctionTypes[{input, {result, attrKey} }]; if (Entry) return Entry; - - return Entry = new (C, arena) FunctionType(Input, Result, - properties, - Info); + + SmallVector params; + AnyFunctionType::decomposeInput(input, params); + void *mem = C.Allocate(sizeof(FunctionType) + + sizeof(AnyFunctionType::Param) * params.size(), + alignof(FunctionType)); + return Entry = new (mem) FunctionType(params, input, result, + properties, info); } // If the input and result types are canonical, then so is the result. -FunctionType::FunctionType(Type input, Type output, +FunctionType::FunctionType(ArrayRef params, + Type input, Type output, RecursiveTypeProperties properties, const ExtInfo &Info) : AnyFunctionType(TypeKind::Function, - (input->isCanonical() && output->isCanonical()) + (isCanonicalFunctionInputType(input) && + output->isCanonical()) ? &input->getASTContext() : nullptr, - input, output, properties, Info) {} + input, output, properties, params.size(), Info) { + std::uninitialized_copy(params.begin(), params.end(), + getTrailingObjects()); +} void GenericFunctionType::Profile(llvm::FoldingSetNodeID &ID, GenericSignature *sig, @@ -3182,6 +3258,25 @@ void GenericFunctionType::Profile(llvm::FoldingSetNodeID &ID, ID.AddInteger(info.getFuncAttrKey()); } +/// If this is a ParenType, unwrap it to produce the underlying type. +/// Otherwise, return \c type. +static Type unwrapParenType(Type type) { + if (auto parenTy = dyn_cast(type.getPointer())) + return parenTy->getUnderlyingType(); + + return type; +} + +GenericFunctionType *GenericFunctionType::get(GenericSignature *sig, + ArrayRef params, + Type result, + const ExtInfo &info, + bool canonicalVararg) { + return get(sig, composeInput(result->getASTContext(), params, + canonicalVararg), + result, info); +} + GenericFunctionType * GenericFunctionType::get(GenericSignature *sig, Type input, @@ -3208,20 +3303,24 @@ GenericFunctionType::get(GenericSignature *sig, // point. auto &moduleForCanonicality = *ctx.TheBuiltinModule; bool isCanonical = sig->isCanonical() - && sig->isCanonicalTypeInContext(input, moduleForCanonicality) + && isCanonicalFunctionInputType(input) + && sig->isCanonicalTypeInContext(unwrapParenType(input), + moduleForCanonicality) && sig->isCanonicalTypeInContext(output, moduleForCanonicality); if (auto result = ctx.Impl.GenericFunctionTypes.FindNodeOrInsertPos(id, insertPos)) { return result; } - - // Allocate storage for the object. - void *mem = ctx.Allocate(sizeof(GenericFunctionType), + + SmallVector params; + AnyFunctionType::decomposeInput(input, params); + void *mem = ctx.Allocate(sizeof(GenericFunctionType) + + sizeof(AnyFunctionType::Param) * params.size(), alignof(GenericFunctionType)); auto properties = getGenericFunctionRecursiveProperties(input, output); - auto result = new (mem) GenericFunctionType(sig, input, output, info, + auto result = new (mem) GenericFunctionType(sig, params, input, output, info, isCanonical ? &ctx : nullptr, properties); @@ -3231,15 +3330,17 @@ GenericFunctionType::get(GenericSignature *sig, GenericFunctionType::GenericFunctionType( GenericSignature *sig, + ArrayRef params, Type input, Type result, const ExtInfo &info, const ASTContext *ctx, RecursiveTypeProperties properties) : AnyFunctionType(TypeKind::GenericFunction, ctx, input, result, - properties, info), - Signature(sig) -{} + properties, params.size(), info), Signature(sig) { + std::uninitialized_copy(params.begin(), params.end(), + getTrailingObjects()); +} GenericTypeParamType *GenericTypeParamType::get(unsigned depth, unsigned index, const ASTContext &ctx) { diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 6232d5eb9a3..af4e858ef10 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -1036,33 +1036,41 @@ namespace { } PrintWithColorRAII(OS, ParenthesisColor) << ')'; } + + void printASTNodes(const ArrayRef &Elements, StringRef Name) { + OS.indent(Indent); + PrintWithColorRAII(OS, ParenthesisColor) << "("; + PrintWithColorRAII(OS, ASTNodeColor) << Name; + for (auto Elt : Elements) { + OS << '\n'; + if (auto *SubExpr = Elt.dyn_cast()) + printRec(SubExpr); + else if (auto *SubStmt = Elt.dyn_cast()) + printRec(SubStmt); + else + printRec(Elt.get()); + } + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } void visitIfConfigDecl(IfConfigDecl *ICD) { - OS.indent(Indent); - PrintWithColorRAII(OS, ParenthesisColor) << '('; - OS << "#if_decl\n"; + printCommon(ICD, "if_config_decl"); Indent += 2; for (auto &Clause : ICD->getClauses()) { + OS << '\n'; + OS.indent(Indent); + PrintWithColorRAII(OS, StmtColor) << (Clause.Cond ? "#if:" : "#else:"); + if (Clause.isActive) + PrintWithColorRAII(OS, DeclModifierColor) << " active"; if (Clause.Cond) { - PrintWithColorRAII(OS, ParenthesisColor) << '('; - OS << "#if:"; - if (Clause.isActive) OS << " active"; OS << "\n"; printRec(Clause.Cond); - } else { - OS << '\n'; - PrintWithColorRAII(OS, ParenthesisColor) << '('; - OS << "#else:"; - if (Clause.isActive) OS << " active"; - OS << "\n"; } - for (auto D : Clause.Elements) { - OS << '\n'; - printRec(D); - } - - PrintWithColorRAII(OS, ParenthesisColor) << ')'; + OS << '\n'; + Indent += 2; + printASTNodes(Clause.Elements, "elements"); + Indent -= 2; } Indent -= 2; @@ -1422,35 +1430,6 @@ public: PrintWithColorRAII(OS, ParenthesisColor) << ')'; } - void visitIfConfigStmt(IfConfigStmt *S) { - printCommon(S, "#if_stmt"); - Indent += 2; - for (auto &Clause : S->getClauses()) { - OS << '\n'; - OS.indent(Indent); - if (Clause.Cond) { - PrintWithColorRAII(OS, ParenthesisColor) << '('; - PrintWithColorRAII(OS, StmtColor) << "#if:"; - if (Clause.isActive) - PrintWithColorRAII(OS, DeclModifierColor) << " active"; - OS << '\n'; - printRec(Clause.Cond); - } else { - PrintWithColorRAII(OS, StmtColor) << "#else"; - if (Clause.isActive) - PrintWithColorRAII(OS, DeclModifierColor) << " active"; - } - - OS << '\n'; - Indent += 2; - printASTNodes(Clause.Elements, "elements"); - Indent -= 2; - } - - Indent -= 2; - PrintWithColorRAII(OS, ParenthesisColor) << ')'; - } - void visitDoStmt(DoStmt *S) { printCommon(S, "do_stmt") << '\n'; printRec(S->getBody()); @@ -1543,9 +1522,12 @@ public: void visitSwitchStmt(SwitchStmt *S) { printCommon(S, "switch_stmt") << '\n'; printRec(S->getSubjectExpr()); - for (CaseStmt *C : S->getCases()) { + for (auto N : S->getRawCases()) { OS << '\n'; - printRec(C); + if (N.is()) + printRec(N.get()); + else + printRec(N.get()); } PrintWithColorRAII(OS, ParenthesisColor) << ')'; } @@ -2656,7 +2638,7 @@ public: for (auto elem : T->getElements()) { OS << '\n'; - printRec(elem); + printRec(elem.Type); } PrintWithColorRAII(OS, ParenthesisColor) << ')'; } diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index b12a9edc09c..9d5b4ab54b7 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -1426,12 +1426,19 @@ void ASTMangler::appendParams(Type ParamsTy, bool forceSingleParam) { return; } if (forceSingleParam && Tuple->getNumElements() > 1) { + if (ParenType *Paren = dyn_cast(ParamsTy.getPointer())) + ParamsTy = Paren->getUnderlyingType(); + appendType(ParamsTy); appendListSeparator(); appendOperator("t"); return; } } + + if (ParenType *Paren = dyn_cast(ParamsTy.getPointer())) + ParamsTy = Paren->getUnderlyingType(); + appendType(ParamsTy); } @@ -1673,7 +1680,8 @@ CanType ASTMangler::getDeclTypeForMangling( auto &C = decl->getASTContext(); if (!decl->hasInterfaceType() || decl->getInterfaceType()->is()) { if (isa(decl)) - return CanFunctionType::get(C.TheErrorType, C.TheErrorType); + return CanFunctionType::get({AnyFunctionType::Param(C.TheErrorType)}, + C.TheErrorType, AnyFunctionType::ExtInfo()); return C.TheErrorType; } @@ -1687,7 +1695,7 @@ CanType ASTMangler::getDeclTypeForMangling( genericParams = sig->getGenericParams(); requirements = sig->getRequirements(); - type = CanFunctionType::get(gft.getInput(), gft.getResult(), + type = CanFunctionType::get(gft->getParams(), gft.getResult(), gft->getExtInfo()); } else { genericParams = {}; diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 8d8133792ac..b845ca21351 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -897,7 +897,8 @@ class PrintAST : public ASTVisitor { M, cast(Current)); } - T = T.subst(subMap, SubstFlags::DesugarMemberTypes); + T = T.subst(subMap, + SubstFlags::DesugarMemberTypes | SubstFlags::UseErrorType); } printType(T); @@ -2317,8 +2318,6 @@ void PrintAST::visitPatternBindingDecl(PatternBindingDecl *decl) { if (anyVar) printDocumentationComment(anyVar); - if (decl->isStatic()) - printStaticKeyword(decl->getCorrectStaticSpelling()); // FIXME: PatternBindingDecls don't have attributes themselves, so just assume // the variables all have the same attributes. This isn't exactly true @@ -2326,6 +2325,12 @@ void PrintAST::visitPatternBindingDecl(PatternBindingDecl *decl) { if (anyVar) { printAttributes(anyVar); printAccessibility(anyVar); + } + + if (decl->isStatic()) + printStaticKeyword(decl->getCorrectStaticSpelling()); + + if (anyVar) { Printer << (anyVar->isSettable(anyVar->getDeclContext()) ? "var " : "let "); } else { Printer << "let "; @@ -2360,7 +2365,21 @@ void PrintAST::visitTopLevelCodeDecl(TopLevelCodeDecl *decl) { } void PrintAST::visitIfConfigDecl(IfConfigDecl *ICD) { - // FIXME: Pretty print #if decls + if (!Options.PrintIfConfig) + return; + + for (auto &Clause : ICD->getClauses()) { + if (&Clause == &*ICD->getClauses().begin()) + Printer << tok::pound_if << " /* condition */"; // FIXME: print condition + else if (Clause.Cond) + Printer << tok::pound_elseif << " /* condition */"; // FIXME: print condition + else + Printer << tok::pound_else; + printASTNodes(Clause.Elements); + Printer.printNewline(); + indent(); + } + Printer << tok::pound_endif; } void PrintAST::visitTypeAliasDecl(TypeAliasDecl *decl) { @@ -3267,27 +3286,6 @@ void PrintAST::visitGuardStmt(GuardStmt *stmt) { visit(stmt->getBody()); } -void PrintAST::visitIfConfigStmt(IfConfigStmt *stmt) { - if (!Options.PrintIfConfig) - return; - - for (auto &Clause : stmt->getClauses()) { - if (&Clause == &*stmt->getClauses().begin()) - Printer << tok::pound_if << " "; // FIXME: print condition - else if (Clause.Cond) - Printer << tok::pound_elseif << ""; // FIXME: print condition - else - Printer << tok::pound_else; - Printer.printNewline(); - if (printASTNodes(Clause.Elements)) { - Printer.printNewline(); - indent(); - } - } - Printer.printNewline(); - Printer << tok::pound_endif; -} - void PrintAST::visitWhileStmt(WhileStmt *stmt) { Printer << tok::kw_while << " "; // FIXME: print condition @@ -3366,8 +3364,11 @@ void PrintAST::visitSwitchStmt(SwitchStmt *stmt) { // FIXME: print subject Printer << "{"; Printer.printNewline(); - for (CaseStmt *C : stmt->getCases()) { - visit(C); + for (auto N : stmt->getRawCases()) { + if (N.is()) + visit(cast(N.get())); + else + visit(cast(N.get())); } Printer.printNewline(); indent(); diff --git a/lib/AST/ASTScope.cpp b/lib/AST/ASTScope.cpp index e40a5a1927a..8be8003353d 100644 --- a/lib/AST/ASTScope.cpp +++ b/lib/AST/ASTScope.cpp @@ -188,24 +188,6 @@ static bool hasAccessors(AbstractStorageDecl *asd) { llvm_unreachable("Unhandled ContinuationKind in switch."); } -/// Determine whether this is a top-level code declaration that isn't just -/// wrapping an #if. -static bool isRealTopLevelCodeDecl(Decl *decl) { - auto topLevelCode = dyn_cast(decl); - if (!topLevelCode) return false; - - // Drop top-level statements containing just an IfConfigStmt. - // FIXME: The modeling of IfConfig is weird. - auto braceStmt = topLevelCode->getBody(); - auto elements = braceStmt->getElements(); - if (elements.size() == 1 && - elements[0].is() && - isa(elements[0].get())) - return false; - - return true; -} - void ASTScope::expand() const { assert(!isExpanded() && "Already expanded the children of this node"); ASTContext &ctx = getASTContext(); @@ -313,7 +295,7 @@ void ASTScope::expand() const { // If the declaration is a top-level code declaration, turn the source // file into a continuation. We're done. - if (isRealTopLevelCodeDecl(decl)) { + if (isa(decl)) { addActiveContinuation(this); break; } @@ -950,7 +932,6 @@ ASTScope *ASTScope::createIfNeeded(const ASTScope *parent, Decl *decl) { } case DeclKind::TopLevelCode: - if (!isRealTopLevelCodeDecl(decl)) return nullptr; return new (ctx) ASTScope(parent, cast(decl)); case DeclKind::Protocol: @@ -1153,7 +1134,6 @@ ASTScope *ASTScope::createIfNeeded(const ASTScope *parent, Stmt *stmt) { case StmtKind::Break: case StmtKind::Continue: case StmtKind::Fallthrough: - case StmtKind::IfConfig: case StmtKind::Fail: case StmtKind::Throw: // Nothing to do for these statements. diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp index b59a7ade234..8bd66bcc1fb 100644 --- a/lib/AST/ASTVerifier.cpp +++ b/lib/AST/ASTVerifier.cpp @@ -463,6 +463,28 @@ public: bool shouldVerifyChecked(Pattern *S) { return S->hasType(); } bool shouldVerifyChecked(Decl *S) { return true; } + // Only verify functions if they have bodies we can safely walk. + // FIXME: This is a bit of a hack; we should be able to check the + // invariants of a parsed body as well. + bool shouldVerify(AbstractFunctionDecl *afd) { + switch (afd->getBodyKind()) { + case AbstractFunctionDecl::BodyKind::None: + case AbstractFunctionDecl::BodyKind::TypeChecked: + case AbstractFunctionDecl::BodyKind::Skipped: + case AbstractFunctionDecl::BodyKind::MemberwiseInitializer: + return true; + + case AbstractFunctionDecl::BodyKind::Unparsed: + case AbstractFunctionDecl::BodyKind::Parsed: + case AbstractFunctionDecl::BodyKind::Synthesize: + if (auto SF = dyn_cast(afd->getModuleScopeContext())) { + return SF->ASTStage < SourceFile::TypeChecked; + } + + return false; + } + } + // Default cases for cleaning up as we exit a node. void cleanup(Expr *E) { } void cleanup(Stmt *S) { } @@ -2575,18 +2597,8 @@ public: // dependent member types. // FIXME: This is a general property of the type system. auto interfaceTy = AFD->getInterfaceType(); - Type unresolvedDependentTy; - interfaceTy.findIf([&](Type type) -> bool { - if (auto dependent = type->getAs()) { - if (dependent->getAssocType() == nullptr) { - unresolvedDependentTy = dependent; - return true; - } - } - return false; - }); - - if (unresolvedDependentTy) { + if (auto unresolvedDependentTy + = interfaceTy->findUnresolvedDependentMemberType()) { Out << "Unresolved dependent member type "; unresolvedDependentTy->print(Out); abort(); @@ -2700,6 +2712,28 @@ public: } } + if (FD->isMutating()) { + if (!FD->isInstanceMember()) { + Out << "mutating function is not an instance member\n"; + abort(); + } + if (FD->getDeclContext()->getAsClassOrClassExtensionContext()) { + Out << "mutating function in a class\n"; + abort(); + } + const ParamDecl *selfParam = FD->getImplicitSelfDecl(); + if (!selfParam->getInterfaceType()->is()) { + Out << "mutating function does not have inout 'self'\n"; + abort(); + } + } else { + const ParamDecl *selfParam = FD->getImplicitSelfDecl(); + if (selfParam && selfParam->getInterfaceType()->is()) { + Out << "non-mutating function has inout 'self'\n"; + abort(); + } + } + verifyCheckedBase(FD); } @@ -3006,23 +3040,23 @@ public: [&]{ S->print(Out); }); } - void checkSourceRanges(IfConfigStmt *S) { - checkSourceRangesBase(S); + void checkSourceRanges(IfConfigDecl *ICD) { + checkSourceRangesBase(ICD); - SourceLoc Location = S->getStartLoc(); - for (auto &Clause : S->getClauses()) { + SourceLoc Location = ICD->getStartLoc(); + for (auto &Clause : ICD->getClauses()) { // Clause start, note that the first clause start location is the // same as that of the whole statement - if (Location == S->getStartLoc()) { + if (Location == ICD->getStartLoc()) { if (Location != Clause.Loc) { - Out << "bad start location of IfConfigStmt first clause\n"; - S->print(Out); + Out << "bad start location of IfConfigDecl first clause\n"; + ICD->print(Out); abort(); } } else { if (!Ctx.SourceMgr.isBeforeInBuffer(Location, Clause.Loc)) { - Out << "bad start location of IfConfigStmt clause\n"; - S->print(Out); + Out << "bad start location of IfConfigDecl clause\n"; + ICD->print(Out); abort(); } } @@ -3032,8 +3066,8 @@ public: Expr *Cond = Clause.Cond; if (Cond) { if (!Ctx.SourceMgr.isBeforeInBuffer(Location, Cond->getStartLoc())) { - Out << "invalid IfConfigStmt clause condition start location\n"; - S->print(Out); + Out << "invalid IfConfigDecl clause condition start location\n"; + ICD->print(Out); abort(); } Location = Cond->getEndLoc(); @@ -3048,8 +3082,8 @@ public: } if (!Ctx.SourceMgr.isBeforeInBuffer(StoredLoc, StartLocation)) { - Out << "invalid IfConfigStmt clause element start location\n"; - S->print(Out); + Out << "invalid IfConfigDecl clause element start location\n"; + ICD->print(Out); abort(); } @@ -3061,9 +3095,9 @@ public: } } - if (Ctx.SourceMgr.isBeforeInBuffer(S->getEndLoc(), Location)) { - Out << "invalid IfConfigStmt end location\n"; - S->print(Out); + if (Ctx.SourceMgr.isBeforeInBuffer(ICD->getEndLoc(), Location)) { + Out << "invalid IfConfigDecl end location\n"; + ICD->print(Out); abort(); } } @@ -3225,7 +3259,7 @@ bool swift::shouldVerify(const Decl *D, const ASTContext &Context) { return true; } - size_t Hash = llvm::hash_value(VD->getNameStr()); + size_t Hash = llvm::hash_value(VD->getBaseName().userFacingName()); return Hash % ProcessCount == ProcessId; #else return false; diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index f17ad7736d0..7a6b38b0029 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -177,7 +177,7 @@ class Traversal : public ASTVisitorgetBody())) DS->setBody(S2); @@ -1460,12 +1452,19 @@ Stmt *Traversal::visitSwitchStmt(SwitchStmt *S) { else return nullptr; - for (CaseStmt *aCase : S->getCases()) { - if (Stmt *aStmt = doIt(aCase)) { - assert(aCase == aStmt && "switch case remap not supported"); - (void)aStmt; - } else - return nullptr; + for (auto N : S->getRawCases()) { + if (Stmt *aCase = N.dyn_cast()) { + assert(isa(aCase)); + if (Stmt *aStmt = doIt(aCase)) { + assert(aCase == aStmt && "switch case remap not supported"); + (void)aStmt; + } else + return nullptr; + } else { + assert(isa(N.get())); + if (doIt(N.get())) + return nullptr; + } } return S; @@ -1646,8 +1645,8 @@ bool Traversal::visitImplicitlyUnwrappedOptionalTypeRepr(ImplicitlyUnwrappedOpti } bool Traversal::visitTupleTypeRepr(TupleTypeRepr *T) { - for (auto elem : T->getElements()) { - if (doIt(elem)) + for (auto &elem : T->getElements()) { + if (doIt(elem.Type)) return true; } return false; diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index 7477ff374d0..d025e086136 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -1028,7 +1028,7 @@ static ValueDecl *getCheckedTruncOperation(ASTContext &Context, return nullptr; Type OverflowBitTy = BuiltinIntegerType::get(1, Context); - TupleTypeElt ResultElts[] = { OutTy, OverflowBitTy }; + TupleTypeElt ResultElts[] = { Type(OutTy), OverflowBitTy }; Type ResultTy = TupleType::get(ResultElts, Context); return getBuiltinFunction(Id, { InTy }, ResultTy); } @@ -1036,7 +1036,7 @@ static ValueDecl *getCheckedTruncOperation(ASTContext &Context, static ValueDecl *getCheckedConversionOperation(ASTContext &Context, Identifier Id, Type Ty) { - auto BuiltinTy = Ty->getAs(); + Type BuiltinTy = Ty->getAs(); if (!BuiltinTy) return nullptr; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 823778984d0..c3b14c5854e 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -457,7 +457,8 @@ bool Decl::isPrivateStdlibDecl(bool whitelistProtocols) const { return false; // If the name has leading underscore then it's a private symbol. - if (VD->getNameStr().startswith("_")) + if (!VD->getBaseName().isSpecial() && + VD->getBaseName().getIdentifier().str().startswith("_")) return true; return false; @@ -1609,47 +1610,21 @@ static Type mapSignatureFunctionType(ASTContext &ctx, Type type, } auto funcTy = type->castTo(); - auto argTy = funcTy->getInput(); - - if (auto tupleTy = argTy->getAs()) { - SmallVector elements; - bool anyChanged = false; - unsigned idx = 0; - // Remap our parameters, and make sure to strip off @escaping - for (const auto &elt : tupleTy->getElements()) { - auto newEltTy = mapSignatureParamType(ctx, elt.getType()); - auto newParamFlags = elt.getParameterFlags().withEscaping(false); - bool exactlyTheSame = newParamFlags == elt.getParameterFlags() && - newEltTy.getPointer() == elt.getType().getPointer(); - - // Don't build up anything if we never see any difference - if (!anyChanged && exactlyTheSame) { - ++idx; - continue; - } - - // First time we see a diff, copy over all the prior - if (!anyChanged && !exactlyTheSame) { - elements.append(tupleTy->getElements().begin(), - tupleTy->getElements().begin() + idx); - anyChanged = true; - } - - elements.emplace_back(newEltTy, elt.getName(), newParamFlags); - } - if (anyChanged) { - argTy = TupleType::get(elements, ctx); - } - } else { - argTy = mapSignatureParamType(ctx, argTy); + SmallVector newParams; + for (const auto ¶m : funcTy->getParams()) { + auto newParamType = mapSignatureParamType(ctx, param.getType()); + ParameterTypeFlags newFlags = param.getParameterFlags().withEscaping(false); + // For the 'self' of a method, strip off 'inout'. if (isMethod) { - // In methods, strip the 'inout' off of 'self' so that mutating and - // non-mutating methods have the same self parameter type. - if (auto inoutTy = argTy->getAs()) { - argTy = inoutTy->getObjectType(); - } + if (auto inoutType = newParamType->getAs()) + newParamType = inoutType->getObjectType(); + + newFlags = newFlags.withInOut(false); } + + AnyFunctionType::Param newParam(newParamType, param.getLabel(), newFlags); + newParams.push_back(newParam); } // Map the result type. @@ -1665,9 +1640,9 @@ static Type mapSignatureFunctionType(ASTContext &ctx, Type type, // Rebuild the resulting function type. if (auto genericFuncTy = dyn_cast(funcTy)) return GenericFunctionType::get(genericFuncTy->getGenericSignature(), - argTy, resultTy, info); + newParams, resultTy, info); - return FunctionType::get(argTy, resultTy, info); + return FunctionType::get(newParams, resultTy, info); } OverloadSignature ValueDecl::getOverloadSignature() const { @@ -2905,10 +2880,13 @@ ProtocolDecl::getInheritedProtocols() const { // Only protocols can appear in the inheritance clause // of a protocol -- anything else should get diagnosed // elsewhere. - if (auto *protoTy = type->getAs()) { - auto *protoDecl = protoTy->getDecl(); - if (known.insert(protoDecl).second) - result.push_back(protoDecl); + if (type->isExistentialType()) { + auto layout = type->getExistentialLayout(); + for (auto protoTy : layout.getProtocols()) { + auto *protoDecl = protoTy->getDecl(); + if (known.insert(protoDecl).second) + result.push_back(protoDecl); + } } } } @@ -3395,7 +3373,9 @@ bool AbstractStorageDecl::isSetterNonMutating() const { switch (getStorageKind()) { case AbstractStorageDecl::Stored: case AbstractStorageDecl::StoredWithTrivialAccessors: - return false; + // Instance member setters are mutating; static property setters and + // top-level setters are not. + return !isInstanceMember(); case AbstractStorageDecl::StoredWithObservers: case AbstractStorageDecl::InheritedWithObservers: @@ -3427,6 +3407,28 @@ FuncDecl *AbstractStorageDecl::getAccessorFunction(AccessorKind kind) const { llvm_unreachable("bad accessor kind!"); } +void AbstractStorageDecl::getAllAccessorFunctions( + SmallVectorImpl &decls) const { + auto tryPush = [&](Decl *decl) { + if (decl) + decls.push_back(decl); + }; + + tryPush(getGetter()); + tryPush(getSetter()); + tryPush(getMaterializeForSetFunc()); + + if (hasObservers()) { + tryPush(getDidSetFunc()); + tryPush(getWillSetFunc()); + } + + if (hasAddressors()) { + tryPush(getAddressor()); + tryPush(getMutableAddressor()); + } +} + void AbstractStorageDecl::configureGetSetRecord(GetSetRecord *getSetInfo, FuncDecl *getter, FuncDecl *setter, diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index 8bfebdebb4d..95bd2af60c3 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -61,17 +61,10 @@ DeclContext::getAsTypeOrTypeExtensionContext() const { auto ED = cast(this); auto type = ED->getExtendedType(); - if (type.isNull() || type->hasError()) + if (!type) return nullptr; - if (auto ND = type->getNominalOrBoundGenericNominal()) - return ND; - - if (auto unbound = dyn_cast(type.getPointer())) { - return unbound->getDecl(); - } - - return nullptr; + return type->getAnyNominal(); } case DeclContextKind::GenericTypeDecl: diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index c32a9ea8558..c99833d3735 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -752,7 +752,7 @@ void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) { } if (auto value = dyn_cast(ppDecl)) { - bufferName += value->getNameStr(); + bufferName += value->getBaseName().userFacingName(); } else if (auto ext = dyn_cast(ppDecl)) { bufferName += ext->getExtendedType().getString(); } diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp index d247fbf4861..5c5a50f2d21 100644 --- a/lib/AST/GenericSignature.cpp +++ b/lib/AST/GenericSignature.cpp @@ -872,7 +872,7 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath( auto pa = reqSigBuilder.resolveArchetype( storedType, - ArchetypeResolutionKind::CompleteWellFormed); + ArchetypeResolutionKind::AlwaysPartial); auto equivClass = pa->getOrCreateEquivalenceClass(); // Find the conformance of this potential archetype to the protocol in @@ -905,7 +905,8 @@ ConformanceAccessPath GenericSignature::getConformanceAccessPath( // We are at an explicit or inferred requirement. assert(source->kind == RequirementSource::Explicit || - source->kind == RequirementSource::Inferred); + source->kind == RequirementSource::Inferred || + source->kind == RequirementSource::QuietlyInferred); // Skip trivial path elements. These occur when querying a requirement // signature. diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp index e749cd7cdfe..05574b7c0c3 100644 --- a/lib/AST/GenericSignatureBuilder.cpp +++ b/lib/AST/GenericSignatureBuilder.cpp @@ -85,11 +85,6 @@ struct GenericSignatureBuilder::Implementation { /// The potential archetypes for the generic parameters in \c GenericParams. SmallVector PotentialArchetypes; - /// The number of nested types that haven't yet been resolved to archetypes. - /// Once all requirements have been added, this will be zero in well-formed - /// code. - unsigned NumUnresolvedNestedTypes = 0; - /// The nested types that have been renamed. SmallVector RenamedNestedTypes; @@ -113,6 +108,7 @@ bool RequirementSource::isAcceptableStorageKind(Kind kind, switch (kind) { case Explicit: case Inferred: + case QuietlyInferred: case RequirementSignatureSelf: case NestedTypeNameMatch: switch (storageKind) { @@ -122,6 +118,7 @@ bool RequirementSource::isAcceptableStorageKind(Kind kind, case StorageKind::StoredType: case StorageKind::ProtocolConformance: case StorageKind::AssociatedTypeDecl: + case StorageKind::None: return false; } @@ -133,6 +130,7 @@ bool RequirementSource::isAcceptableStorageKind(Kind kind, case StorageKind::RootArchetype: case StorageKind::StoredType: case StorageKind::ProtocolConformance: + case StorageKind::None: return false; } @@ -145,6 +143,7 @@ bool RequirementSource::isAcceptableStorageKind(Kind kind, case StorageKind::RootArchetype: case StorageKind::ProtocolConformance: case StorageKind::AssociatedTypeDecl: + case StorageKind::None: return false; } @@ -156,6 +155,19 @@ bool RequirementSource::isAcceptableStorageKind(Kind kind, case StorageKind::RootArchetype: case StorageKind::StoredType: + case StorageKind::AssociatedTypeDecl: + case StorageKind::None: + return false; + } + + case Derived: + switch (storageKind) { + case StorageKind::None: + return true; + + case StorageKind::RootArchetype: + case StorageKind::StoredType: + case StorageKind::ProtocolConformance: case StorageKind::AssociatedTypeDecl: return false; } @@ -167,6 +179,9 @@ bool RequirementSource::isAcceptableStorageKind(Kind kind, const void *RequirementSource::getOpaqueStorage1() const { switch (storageKind) { + case StorageKind::None: + return nullptr; + case StorageKind::RootArchetype: return storage.rootArchetype; @@ -200,13 +215,16 @@ const void *RequirementSource::getOpaqueStorage3() const { return nullptr; } -bool RequirementSource::isInferredRequirement() const { +bool RequirementSource::isInferredRequirement(bool includeQuietInferred) const { for (auto source = this; source; source = source->parent) { switch (source->kind) { case Inferred: case InferredProtocolRequirement: return true; + case QuietlyInferred: + return includeQuietInferred; + case Concrete: case Explicit: case NestedTypeNameMatch: @@ -214,6 +232,7 @@ bool RequirementSource::isInferredRequirement() const { case ProtocolRequirement: case RequirementSignatureSelf: case Superclass: + case Derived: break; } } @@ -222,7 +241,7 @@ bool RequirementSource::isInferredRequirement() const { } unsigned RequirementSource::classifyDiagKind() const { - if (isInferredRequirement()) return 2; + if (isInferredRequirement(/*includeQuietInferred=*/false)) return 2; if (isDerivedRequirement()) return 1; return 0; } @@ -231,6 +250,7 @@ bool RequirementSource::isDerivedRequirement() const { switch (kind) { case Explicit: case Inferred: + case QuietlyInferred: return false; case NestedTypeNameMatch: @@ -238,6 +258,7 @@ bool RequirementSource::isDerivedRequirement() const { case Superclass: case Concrete: case RequirementSignatureSelf: + case Derived: return true; case ProtocolRequirement: @@ -263,6 +284,7 @@ bool RequirementSource::isSelfDerivedSource(PotentialArchetype *pa, switch (source->kind) { case RequirementSource::Explicit: case RequirementSource::Inferred: + case RequirementSource::QuietlyInferred: case RequirementSource::RequirementSignatureSelf: for (auto parent = currentPA->getParent(); parent; parent = parent->getParent()) { @@ -285,6 +307,7 @@ bool RequirementSource::isSelfDerivedSource(PotentialArchetype *pa, case RequirementSource::NestedTypeNameMatch: case RequirementSource::Concrete: case RequirementSource::Superclass: + case RequirementSource::Derived: return false; } }) == nullptr; @@ -394,9 +417,11 @@ bool RequirementSource::isSelfDerivedConformance( case Concrete: case Superclass: case Parent: + case Derived: return false; case Explicit: case Inferred: + case QuietlyInferred: case NestedTypeNameMatch: case RequirementSignatureSelf: rootPA = parentPA; @@ -464,14 +489,15 @@ const RequirementSource *RequirementSource::forExplicit( const RequirementSource *RequirementSource::forInferred( PotentialArchetype *root, - const TypeRepr *typeRepr) { + const TypeRepr *typeRepr, + bool quietly) { WrittenRequirementLoc writtenLoc = typeRepr; auto &builder = *root->getBuilder(); REQUIREMENT_SOURCE_FACTORY_BODY( - (nodeID, Inferred, nullptr, root, - writtenLoc.getOpaqueValue(), nullptr), - (Inferred, root, nullptr, writtenLoc), - 0, writtenLoc); + (nodeID, quietly ? QuietlyInferred : Inferred, nullptr, root, + writtenLoc.getOpaqueValue(), nullptr), + (quietly ? QuietlyInferred : Inferred, root, nullptr, writtenLoc), + 0, writtenLoc); } const RequirementSource *RequirementSource::forRequirementSignature( @@ -518,20 +544,21 @@ const RequirementSource *RequirementSource::viaProtocolRequirement( } const RequirementSource *RequirementSource::viaSuperclass( - GenericSignatureBuilder &builder, - ProtocolConformance *conformance) const { + GenericSignatureBuilder &builder, + ProtocolConformanceRef conformance) const { REQUIREMENT_SOURCE_FACTORY_BODY( - (nodeID, Superclass, this, conformance, + (nodeID, Superclass, this, conformance.getOpaqueValue(), nullptr, nullptr), (Superclass, this, conformance), 0, WrittenRequirementLoc()); } const RequirementSource *RequirementSource::viaConcrete( - GenericSignatureBuilder &builder, - ProtocolConformance *conformance) const { + GenericSignatureBuilder &builder, + ProtocolConformanceRef conformance) const { REQUIREMENT_SOURCE_FACTORY_BODY( - (nodeID, Concrete, this, conformance, nullptr, nullptr), + (nodeID, Concrete, this, conformance.getOpaqueValue(), + nullptr, nullptr), (Concrete, this, conformance), 0, WrittenRequirementLoc()); } @@ -545,6 +572,14 @@ const RequirementSource *RequirementSource::viaParent( 0, WrittenRequirementLoc()); } +const RequirementSource *RequirementSource::viaDerived( + GenericSignatureBuilder &builder) const { + REQUIREMENT_SOURCE_FACTORY_BODY( + (nodeID, Derived, this, nullptr, nullptr, nullptr), + (Derived, this), + 0, WrittenRequirementLoc()); +} + #undef REQUIREMENT_SOURCE_FACTORY_BODY const RequirementSource *RequirementSource::getRoot() const { @@ -589,6 +624,7 @@ RequirementSource::visitPotentialArchetypesAlongPath( case RequirementSource::NestedTypeNameMatch: case RequirementSource::Explicit: case RequirementSource::Inferred: + case RequirementSource::QuietlyInferred: case RequirementSource::RequirementSignatureSelf: { auto rootPA = getRootPotentialArchetype(); if (visitor(rootPA, this)) return nullptr; @@ -598,6 +634,7 @@ RequirementSource::visitPotentialArchetypesAlongPath( case RequirementSource::Concrete: case RequirementSource::Superclass: + case RequirementSource::Derived: return parent->visitPotentialArchetypesAlongPath(visitor); case RequirementSource::ProtocolRequirement: @@ -614,6 +651,7 @@ RequirementSource::visitPotentialArchetypesAlongPath( Type RequirementSource::getStoredType() const { switch (storageKind) { + case StorageKind::None: case StorageKind::RootArchetype: case StorageKind::ProtocolConformance: case StorageKind::AssociatedTypeDecl: @@ -628,6 +666,9 @@ Type RequirementSource::getStoredType() const { ProtocolDecl *RequirementSource::getProtocolDecl() const { switch (storageKind) { + case StorageKind::None: + return nullptr; + case StorageKind::RootArchetype: if (kind == RequirementSignatureSelf) return getTrailingObjects()[0]; @@ -639,10 +680,7 @@ ProtocolDecl *RequirementSource::getProtocolDecl() const { return nullptr; case StorageKind::ProtocolConformance: - if (storage.conformance) - return storage.conformance->getProtocol(); - - return nullptr; + return getProtocolConformance().getRequirement(); case StorageKind::AssociatedTypeDecl: return storage.assocType->getProtocol(); @@ -777,6 +815,10 @@ void RequirementSource::print(llvm::raw_ostream &out, out << "Inferred"; break; + case QuietlyInferred: + out << "Quietly inferred"; + break; + case NestedTypeNameMatch: out << "Nested type match"; break; @@ -800,6 +842,10 @@ void RequirementSource::print(llvm::raw_ostream &out, case Superclass: out << "Superclass"; break; + + case Derived: + out << "Derived"; + break; } // Local function to dump a source location, if we can. @@ -814,6 +860,7 @@ void RequirementSource::print(llvm::raw_ostream &out, }; switch (storageKind) { + case StorageKind::None: case StorageKind::RootArchetype: break; @@ -824,12 +871,16 @@ void RequirementSource::print(llvm::raw_ostream &out, } break; - case StorageKind::ProtocolConformance: - if (storage.conformance) { - out << " (" << storage.conformance->getType()->getString() << ": " - << storage.conformance->getProtocol()->getName() << ")"; + case StorageKind::ProtocolConformance: { + auto conformance = getProtocolConformance(); + if (conformance.isConcrete()) { + out << " (" << conformance.getConcrete()->getType()->getString() << ": " + << conformance.getConcrete()->getProtocol()->getName() << ")"; + } else { + out << " (abstract " << conformance.getRequirement()->getName() << ")"; } break; + } case StorageKind::AssociatedTypeDecl: out << " (" << storage.assocType->getProtocol()->getName() @@ -873,7 +924,12 @@ const RequirementSource *FloatingRequirementSource::getSource( return RequirementSource::forAbstract(pa); case Inferred: - return RequirementSource::forInferred(pa, storage.get()); + return RequirementSource::forInferred(pa, storage.get(), + /*quietly=*/false); + + case QuietlyInferred: + return RequirementSource::forInferred(pa, storage.get(), + /*quietly=*/true); case AbstractProtocol: { // Derive the dependent type on which this requirement was written. It is @@ -926,6 +982,7 @@ bool FloatingRequirementSource::isExplicit() const { return true; case Inferred: + case QuietlyInferred: case NestedTypeNameMatch: return false; @@ -941,11 +998,13 @@ bool FloatingRequirementSource::isExplicit() const { case RequirementSource::Concrete: case RequirementSource::Explicit: case RequirementSource::Inferred: + case RequirementSource::QuietlyInferred: case RequirementSource::NestedTypeNameMatch: case RequirementSource::Parent: case RequirementSource::ProtocolRequirement: case RequirementSource::InferredProtocolRequirement: case RequirementSource::Superclass: + case RequirementSource::Derived: return false; } @@ -959,12 +1018,14 @@ bool FloatingRequirementSource::isExplicit() const { == RequirementSource::RequirementSignatureSelf; case RequirementSource::Inferred: + case RequirementSource::QuietlyInferred: case RequirementSource::InferredProtocolRequirement: case RequirementSource::RequirementSignatureSelf: case RequirementSource::Concrete: case RequirementSource::NestedTypeNameMatch: case RequirementSource::Parent: case RequirementSource::Superclass: + case RequirementSource::Derived: return false; } } @@ -972,12 +1033,13 @@ bool FloatingRequirementSource::isExplicit() const { FloatingRequirementSource FloatingRequirementSource::asInferred( - const TypeRepr *typeRepr) const { + const TypeRepr *typeRepr) const { switch (kind) { case Explicit: - return forInferred(typeRepr); + return forInferred(typeRepr, /*quietly=*/false); case Inferred: + case QuietlyInferred: case Resolved: case NestedTypeNameMatch: return *this; @@ -1020,11 +1082,34 @@ bool FloatingRequirementSource::isRecursive( pa = parent; } + + // Also check the root type. + grossCount = 0; + for (Type type = rootType; + auto depTy = type->getAs(); + type = depTy->getBase()) { + if (depTy->getName() == nestedName) { + if (++grossCount > 4) { + ++NumRecursive; + return true; + } + } + } } return false; } +PotentialArchetype::PotentialArchetype(PotentialArchetype *parent, + Identifier name) + : parentOrBuilder(parent), identifier(name), isUnresolvedNestedType(true), + IsRecursive(false), Invalid(false), + DiagnosedRename(false) +{ + assert(parent != nullptr && "Not an associated type?"); + getBuilder()->recordUnresolvedType(this); +} + GenericSignatureBuilder::PotentialArchetype::~PotentialArchetype() { ++NumPotentialArchetypes; @@ -1089,9 +1174,6 @@ void GenericSignatureBuilder::PotentialArchetype::resolveAssociatedType( isUnresolvedNestedType = false; identifier.assocTypeOrConcrete = assocType; assert(assocType->getName() == getNestedName()); - assert(builder.Impl->NumUnresolvedNestedTypes > 0 && - "Mismatch in number of unresolved nested types"); - --builder.Impl->NumUnresolvedNestedTypes; } void GenericSignatureBuilder::PotentialArchetype::resolveConcreteType( @@ -1101,9 +1183,6 @@ void GenericSignatureBuilder::PotentialArchetype::resolveConcreteType( isUnresolvedNestedType = false; identifier.assocTypeOrConcrete = concreteDecl; assert(concreteDecl->getName() == getNestedName()); - assert(builder.Impl->NumUnresolvedNestedTypes > 0 && - "Mismatch in number of unresolved nested types"); - --builder.Impl->NumUnresolvedNestedTypes; } Optional @@ -1202,6 +1281,13 @@ void EquivalenceClass::dump() const { dump(llvm::errs()); } +void GenericSignatureBuilder::recordUnresolvedType( + PotentialArchetype *unresolvedPA) { + Impl->DelayedRequirements.push_back( + {DelayedRequirement::Unresolved, unresolvedPA, RequirementRHS(), + FloatingRequirementSource::forAbstract()}); +} + ConstraintResult GenericSignatureBuilder::handleUnresolvedRequirement( RequirementKind kind, UnresolvedType lhs, @@ -1209,18 +1295,74 @@ ConstraintResult GenericSignatureBuilder::handleUnresolvedRequirement( FloatingRequirementSource source, UnresolvedHandlingKind unresolvedHandling) { switch (unresolvedHandling) { - case UnresolvedHandlingKind::GenerateConstraints: - Impl->DelayedRequirements.push_back({kind, lhs, rhs, source}); + case UnresolvedHandlingKind::GenerateConstraints: { + DelayedRequirement::Kind delayedKind; + switch (kind) { + case RequirementKind::Conformance: + case RequirementKind::Superclass: + delayedKind = DelayedRequirement::Type; + break; + + case RequirementKind::Layout: + delayedKind = DelayedRequirement::Layout; + break; + + case RequirementKind::SameType: + delayedKind = DelayedRequirement::SameType; + break; + } + Impl->DelayedRequirements.push_back({delayedKind, lhs, rhs, source}); return ConstraintResult::Resolved; + } case UnresolvedHandlingKind::ReturnUnresolved: return ConstraintResult::Unresolved; } } +const RequirementSource * +GenericSignatureBuilder::resolveConcreteConformance(PotentialArchetype *pa, + ProtocolDecl *proto) { + auto concrete = pa->getConcreteType(); + if (!concrete) return nullptr; + + // Conformance to this protocol is redundant; update the requirement source + // appropriately. + auto paEquivClass = pa->getOrCreateEquivalenceClass(); + const RequirementSource *concreteSource; + if (auto writtenSource = + paEquivClass->findAnyConcreteConstraintAsWritten(pa)) + concreteSource = writtenSource->source; + else + concreteSource = paEquivClass->concreteTypeConstraints.front().source; + + // Lookup the conformance of the concrete type to this protocol. + auto conformance = + getLookupConformanceFn()(pa->getDependentType({ }, /*allowUnresolved=*/true) + ->getCanonicalType(), + concrete, + proto->getDeclaredInterfaceType() + ->castTo()); + if (!conformance) { + if (!concrete->hasError() && concreteSource->getLoc().isValid()) { + Diags.diagnose(concreteSource->getLoc(), + diag::requires_generic_param_same_type_does_not_conform, + concrete, proto->getName()); + } + + paEquivClass->invalidConcreteType = true; + return nullptr; + } + + concreteSource = concreteSource->viaConcrete(*this, *conformance); + paEquivClass->conformsTo[proto].push_back({pa, proto, concreteSource}); + ++NumConformanceConstraints; + return concreteSource; +} + const RequirementSource *GenericSignatureBuilder::resolveSuperConformance( - GenericSignatureBuilder::PotentialArchetype *pa, - ProtocolDecl *proto) { + PotentialArchetype *pa, + ProtocolDecl *proto) { // Get the superclass constraint. Type superclass = pa->getSuperclass(); if (!superclass) return nullptr; @@ -1245,7 +1387,7 @@ const RequirementSource *GenericSignatureBuilder::resolveSuperConformance( superclassSource = paEquivClass->superclassConstraints.front().source; superclassSource = - superclassSource->viaSuperclass(*this, conformance->getConcrete()); + superclassSource->viaSuperclass(*this, *conformance); paEquivClass->conformsTo[proto].push_back({pa, proto, superclassSource}); ++NumConformanceConstraints; return superclassSource; @@ -1289,7 +1431,7 @@ static void maybeAddSameTypeRequirementForNestedType( if (!assocType) return; // Dig out the type witness. - auto superConformance = superSource->getProtocolConformance(); + auto superConformance = superSource->getProtocolConformance().getConcrete(); auto concreteType = superConformance->getTypeWitness(assocType, builder.getLazyResolver()); if (!concreteType) return; @@ -1334,14 +1476,18 @@ bool PotentialArchetype::addConformance(ProtocolDecl *proto, ++NumConformanceConstraints; ++NumConformances; - // Determine whether there is a superclass constraint where the - // superclass conforms to this protocol. - (void)getBuilder()->resolveSuperConformance(this, proto); + // If there is a concrete type that resolves this conformance requirement, + // record the conformance. + if (!builder.resolveConcreteConformance(this, proto)) { + // Otherwise, determine whether there is a superclass constraint where the + // superclass conforms to this protocol. + (void)builder.resolveSuperConformance(this, proto); + } // Resolve any existing nested types that need it. for (auto &nested : NestedTypes) { (void)updateNestedTypeForConformance(nested.first, proto, - NestedTypeUpdate::ResolveExisting); + ArchetypeResolutionKind::AlreadyKnown); } return true; @@ -1409,26 +1555,35 @@ static int compareAssociatedTypes(AssociatedTypeDecl *assocType1, return 0; } +/// Whether there are any concrete type declarations in the potential archetype. +static bool hasConcreteDecls(const PotentialArchetype *pa) { + auto parent = pa->getParent(); + if (!parent) return false; + + if (pa->getConcreteTypeDecl()) + return true; + + return hasConcreteDecls(parent); +} + /// Canonical ordering for dependent types in generic signatures. static int compareDependentTypes(PotentialArchetype * const* pa, - PotentialArchetype * const* pb) { + PotentialArchetype * const* pb, + bool outermost) { auto a = *pa, b = *pb; // Fast-path check for equality. if (a == b) return 0; - // Concrete types must be ordered *after* everything else, to ensure they - // don't become representatives in the case where a concrete type is equated - // with an associated type. - if (a->getParent() && b->getParent() && - !!a->getConcreteTypeDecl() != !!b->getConcreteTypeDecl()) - return a->getConcreteTypeDecl() ? +1 : -1; - - // Types that are equivalent to concrete types follow types that are still - // type parameters. - if (a->isConcreteType() != b->isConcreteType()) - return a->isConcreteType() ? +1 : -1; + // If one has concrete declarations somewhere but the other does not, + // prefer the one without concrete declarations. + if (outermost) { + bool aHasConcreteDecls = hasConcreteDecls(a); + bool bHasConcreteDecls = hasConcreteDecls(b); + if (aHasConcreteDecls != bHasConcreteDecls) + return aHasConcreteDecls ? +1 : -1; + } // Ordering is as follows: // - Generic params @@ -1444,9 +1599,21 @@ static int compareDependentTypes(PotentialArchetype * const* pa, auto ppb = b->getParent(); // - by base, so t_0_n.`P.T` < t_1_m.`P.T` - if (int compareBases = compareDependentTypes(&ppa, &ppb)) + if (int compareBases = compareDependentTypes(&ppa, &ppb, /*outermost=*/false)) return compareBases; + // Types that are equivalent to concrete types follow types that are still + // type parameters. + if (a->isConcreteType() != b->isConcreteType()) + return a->isConcreteType() ? +1 : -1; + + // Concrete types must be ordered *after* everything else, to ensure they + // don't become representatives in the case where a concrete type is equated + // with an associated type. + if (a->getParent() && b->getParent() && + !!a->getConcreteTypeDecl() != !!b->getConcreteTypeDecl()) + return a->getConcreteTypeDecl() ? +1 : -1; + // - by name, so t_n_m.`P.T` < t_n_m.`P.U` if (int compareNames = a->getNestedName().str().compare( b->getNestedName().str())) @@ -1490,6 +1657,11 @@ static int compareDependentTypes(PotentialArchetype * const* pa, llvm_unreachable("potential archetype total order failure"); } +static int compareDependentTypes(PotentialArchetype * const* pa, + PotentialArchetype * const* pb) { + return compareDependentTypes(pa, pb, /*outermost=*/true); +} + PotentialArchetype *PotentialArchetype::getArchetypeAnchor( GenericSignatureBuilder &builder) { // Find the best archetype within this equivalence class. @@ -1498,9 +1670,10 @@ PotentialArchetype *PotentialArchetype::getArchetypeAnchor( if (auto parent = getParent()) { // For a nested type, retrieve the parent archetype anchor first. auto parentAnchor = parent->getArchetypeAnchor(builder); + assert(parentAnchor->getNestingDepth() <= parent->getNestingDepth()); anchor = parentAnchor->getNestedArchetypeAnchor( - getNestedName(), builder, - NestedTypeUpdate::ResolveExisting); + getNestedName(), builder, + ArchetypeResolutionKind::CompleteWellFormed); // FIXME: Hack for cases where we couldn't resolve the nested type. if (!anchor) @@ -1517,7 +1690,6 @@ PotentialArchetype *PotentialArchetype::getArchetypeAnchor( equivClass->archetypeAnchorCache.numMembers == equivClass->members.size()) { ++NumArchetypeAnchorCacheHits; - return equivClass->archetypeAnchorCache.anchor; } @@ -1545,31 +1717,10 @@ PotentialArchetype *PotentialArchetype::getArchetypeAnchor( } namespace { - /// Function object to diagnose a conflict in same-type constraints for a - /// given potential archetype. - struct DiagnoseSameTypeConflict { - DiagnosticEngine &diags; - const RequirementSource *source; - PotentialArchetype *pa; - - void operator()(Type type1, Type type2) const { - if (pa->getParent() && pa->getConcreteTypeDecl() && - source->getLoc().isInvalid()) { - diags.diagnose(pa->getConcreteTypeDecl()->getLoc(), - diag::protocol_typealias_conflict, - pa->getConcreteTypeDecl()->getName(), - type1, type2); - return; - } - - if (source->getLoc().isValid()) { - diags.diagnose(source->getLoc(), - diag::requires_same_type_conflict, - pa->isGenericParam(), - pa->getDependentType(/*FIXME: */{ }, true), - type1, type2); - } - } + /// Function object used to suppress conflict diagnoses when we know we'll + /// see them again later. + struct SameTypeConflictCheckedLater { + void operator()(Type type1, Type type2) const { } }; } // end anonymous namespace @@ -1577,12 +1728,11 @@ namespace { // parent PA that has a concrete type. static void concretizeNestedTypeFromConcreteParent( GenericSignatureBuilder::PotentialArchetype *parent, - const RequirementSource *parentConcreteSource, GenericSignatureBuilder::PotentialArchetype *nestedPA, - GenericSignatureBuilder &builder, - llvm::function_ref - lookupConformance) { - auto concreteParent = parent->getConcreteType(); + GenericSignatureBuilder &builder) { + auto parentEquiv = parent->getEquivalenceClassIfPresent(); + assert(parentEquiv && "can't have a concrete type without an equiv class"); + auto concreteParent = parentEquiv->concreteType; assert(concreteParent && "attempting to resolve concrete nested type of non-concrete PA"); @@ -1591,11 +1741,22 @@ static void concretizeNestedTypeFromConcreteParent( auto assocType = nestedPA->getResolvedAssociatedType(); if (!assocType) return; - auto source = parentConcreteSource->viaConcrete(builder, /*FIXME: */nullptr) - ->viaParent(builder, assocType); + auto proto = assocType->getProtocol(); + assert(parentEquiv->conformsTo.count(proto) > 0 && + "No conformance requirement"); + const RequirementSource *parentConcreteSource = nullptr; + for (const auto &constraint : parentEquiv->conformsTo.find(proto)->second) { + if (constraint.source->kind == RequirementSource::Concrete) { + parentConcreteSource = constraint.source; + } + } - // FIXME: Get the conformance from the parent. - auto conformance = lookupConformance(assocType->getProtocol()); + // Error condition: parent did not conform to this protocol, so there is no + // way to resolve the nested type via concrete conformance. + if (!parentConcreteSource) return; + + auto source = parentConcreteSource->viaParent(builder, assocType); + auto conformance = parentConcreteSource->getProtocolConformance(); Type witnessType; if (conformance.isConcrete()) { @@ -1609,14 +1770,12 @@ static void concretizeNestedTypeFromConcreteParent( builder.addSameTypeRequirement( nestedPA, witnessType, source, GenericSignatureBuilder::UnresolvedHandlingKind::GenerateConstraints, - DiagnoseSameTypeConflict{ - builder.getASTContext().Diags, - source, nestedPA - }); + SameTypeConflictCheckedLater()); } PotentialArchetype *PotentialArchetype::getNestedType( Identifier nestedName, + ArchetypeResolutionKind kind, GenericSignatureBuilder &builder) { // If we already have a nested type with this name, return it. auto known = NestedTypes.find(nestedName); @@ -1625,27 +1784,27 @@ PotentialArchetype *PotentialArchetype::getNestedType( // Retrieve the nested archetype anchor, which is the best choice (so far) // for this nested type. - return getNestedArchetypeAnchor(nestedName, builder); + return getNestedArchetypeAnchor(nestedName, builder, kind); } PotentialArchetype *PotentialArchetype::getNestedType( AssociatedTypeDecl *assocType, GenericSignatureBuilder &builder) { return updateNestedTypeForConformance(assocType, - NestedTypeUpdate::AddIfMissing); + ArchetypeResolutionKind::WellFormed); } PotentialArchetype *PotentialArchetype::getNestedType( TypeDecl *getConcreteTypeDecl, GenericSignatureBuilder &builder) { return updateNestedTypeForConformance(getConcreteTypeDecl, - NestedTypeUpdate::AddIfMissing); + ArchetypeResolutionKind::WellFormed); } PotentialArchetype *PotentialArchetype::getNestedArchetypeAnchor( Identifier name, GenericSignatureBuilder &builder, - NestedTypeUpdate kind) { + ArchetypeResolutionKind kind) { // Look for the best associated type or concrete type within the protocols // we know about. AssociatedTypeDecl *bestAssocType = nullptr; @@ -1689,8 +1848,7 @@ PotentialArchetype *PotentialArchetype::getNestedArchetypeAnchor( // If we found an associated type, use it. PotentialArchetype *resultPA = nullptr; if (bestAssocType) { - resultPA = updateNestedTypeForConformance(bestAssocType, - NestedTypeUpdate::AddIfMissing); + resultPA = updateNestedTypeForConformance(bestAssocType, kind); } // If we have an associated type, drop any concrete decls that aren't in @@ -1730,8 +1888,9 @@ PotentialArchetype *PotentialArchetype::getNestedArchetypeAnchor( // Update for all of the concrete decls with this name, which will introduce // various same-type constraints. for (auto concreteDecl : concreteDecls) { - auto concreteDeclPA = updateNestedTypeForConformance(concreteDecl, - NestedTypeUpdate::AddIfMissing); + auto concreteDeclPA = updateNestedTypeForConformance( + concreteDecl, + ArchetypeResolutionKind::WellFormed); if (!resultPA && concreteDecl == bestConcreteDecl) resultPA = concreteDeclPA; } @@ -1741,12 +1900,12 @@ PotentialArchetype *PotentialArchetype::getNestedArchetypeAnchor( // Check whether we can add a missing nested type for this case. switch (kind) { - case NestedTypeUpdate::AddIfBetterAnchor: - case NestedTypeUpdate::AddIfMissing: + case ArchetypeResolutionKind::AlwaysPartial: break; - case NestedTypeUpdate::ResolveExisting: - // Don't add a new type; + case ArchetypeResolutionKind::WellFormed: + case ArchetypeResolutionKind::CompleteWellFormed: + case ArchetypeResolutionKind::AlreadyKnown: return nullptr; } @@ -1754,11 +1913,10 @@ PotentialArchetype *PotentialArchetype::getNestedArchetypeAnchor( auto &nested = NestedTypes[name]; if (nested.empty()) { nested.push_back(new PotentialArchetype(this, name)); - ++builder.Impl->NumUnresolvedNestedTypes; auto rep = getRepresentative(); if (rep != this) { - auto existingPA = rep->getNestedType(name, builder); + auto existingPA = rep->getNestedType(name, kind, builder); auto sameNamedSource = RequirementSource::forNestedTypeNameMatch(existingPA); @@ -1773,9 +1931,9 @@ PotentialArchetype *PotentialArchetype::getNestedArchetypeAnchor( PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance( - Identifier name, - ProtocolDecl *proto, - NestedTypeUpdate kind) { + Identifier name, + ProtocolDecl *proto, + ArchetypeResolutionKind kind) { /// Determine whether there is an associated type or concrete type with this /// name in this protocol. If not, there's nothing to do. AssociatedTypeDecl *assocType = nullptr; @@ -1808,7 +1966,7 @@ PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance( PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance( PointerUnion type, - NestedTypeUpdate kind) { + ArchetypeResolutionKind kind) { auto *assocType = type.dyn_cast(); auto *concreteDecl = type.dyn_cast(); if (!assocType && !concreteDecl) @@ -1860,13 +2018,9 @@ PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance( // If we don't have a result potential archetype yet, we may need to add one. if (!resultPA) { switch (kind) { - case NestedTypeUpdate::AddIfBetterAnchor: - // FIXME: The loop above should have kept track of whether this type - // would make a better anchor, so we can bail out here if the answer is - // "no". - LLVM_FALLTHROUGH; - - case NestedTypeUpdate::AddIfMissing: { + case ArchetypeResolutionKind::AlwaysPartial: + case ArchetypeResolutionKind::CompleteWellFormed: + case ArchetypeResolutionKind::WellFormed: { if (assocType) resultPA = new PotentialArchetype(this, assocType); else @@ -1886,7 +2040,7 @@ PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance( if (assocType) existingPA = rep->getNestedType(assocType, builder); else - existingPA = rep->getNestedType(name, builder); + existingPA = rep->getNestedType(concreteDecl, builder); } } @@ -1902,7 +2056,7 @@ PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance( break; } - case NestedTypeUpdate::ResolveExisting: + case ArchetypeResolutionKind::AlreadyKnown: break; } } @@ -1968,21 +2122,7 @@ PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance( // FIXME: This feels like massive overkill. Why do we have to loop? if (isConcreteType()) { for (auto equivT : getRepresentative()->getEquivalenceClassMembers()) { - concretizeNestedTypeFromConcreteParent( - equivT, RequirementSource::forNestedTypeNameMatch(this), - resultPA, builder, - [&](ProtocolDecl *proto) -> ProtocolConformanceRef { - auto depTy = resultPA->getDependentType({}, - /*allowUnresolved=*/true) - ->getCanonicalType(); - auto protocolTy = - proto->getDeclaredInterfaceType()->castTo(); - auto conformance = builder.getLookupConformanceFn()( - depTy, getConcreteType(), protocolTy); - assert(conformance && - "failed to find PA's conformance to known protocol"); - return *conformance; - }); + concretizeNestedTypeFromConcreteParent(equivT, resultPA, builder); } } } @@ -2164,7 +2304,10 @@ void ArchetypeType::resolveNestedType( auto parentPA = builder.resolveArchetype(interfaceType, ArchetypeResolutionKind::CompleteWellFormed); - auto memberPA = parentPA->getNestedType(nested.first, builder); + auto memberPA = parentPA->getNestedType( + nested.first, + ArchetypeResolutionKind::CompleteWellFormed, + builder); auto result = memberPA->getTypeInContext(builder, genericEnv); assert(!nested.second || nested.second->isEqual(result) || @@ -2306,7 +2449,8 @@ void GenericSignatureBuilder::PotentialArchetype::dump(llvm::raw_ostream &Out, #pragma mark Equivalence classes EquivalenceClass::EquivalenceClass(PotentialArchetype *representative) - : recursiveConcreteType(false), recursiveSuperclassType(false) + : recursiveConcreteType(false), invalidConcreteType(false), + recursiveSuperclassType(false) { members.push_back(representative); } @@ -2363,39 +2507,13 @@ PotentialArchetype *GenericSignatureBuilder::resolveArchetype( if (!base) return nullptr; - // Figure out what kind of nested type update we want. - typedef PotentialArchetype::NestedTypeUpdate NestedTypeUpdate; - NestedTypeUpdate updateKind; - switch (resolutionKind) { - case ArchetypeResolutionKind::AlreadyKnown: - updateKind = NestedTypeUpdate::ResolveExisting; - break; - - case ArchetypeResolutionKind::AlwaysPartial: - case ArchetypeResolutionKind::CompleteWellFormed: - updateKind = NestedTypeUpdate::AddIfMissing; - break; - } - // If we know the associated type already, get that specific type. if (auto assocType = dependentMember->getAssocType()) - return base->updateNestedTypeForConformance(assocType, updateKind); + return base->updateNestedTypeForConformance(assocType, resolutionKind); // Resolve based on name alone. auto name = dependentMember->getName(); - switch (resolutionKind) { - case ArchetypeResolutionKind::AlreadyKnown: { - auto known = base->NestedTypes.find(name); - if (known == base->NestedTypes.end()) - return nullptr; - - return known->second.front(); - } - - case ArchetypeResolutionKind::AlwaysPartial: - case ArchetypeResolutionKind::CompleteWellFormed: - return base->getNestedArchetypeAnchor(name, *this, updateKind); - } + return base->getNestedArchetypeAnchor(name, *this, resolutionKind); } return nullptr; @@ -2708,7 +2826,20 @@ ConstraintResult GenericSignatureBuilder::addConformanceRequirement( continue; } - // FIXME: this is a weird situation. + // We inherited a type; this associated type will be identical + // to that typealias. + if (Source->kind == RequirementSource::RequirementSignatureSelf) { + auto inheritedOwningDecl = + inheritedType->getDeclContext() + ->getAsNominalTypeOrNominalTypeExtensionContext(); + Diags.diagnose(assocTypeDecl, + diag::associated_type_override_typealias, + assocTypeDecl->getFullName(), + inheritedOwningDecl->getDescriptiveKind(), + inheritedOwningDecl->getDeclaredInterfaceType()); + } + + addInferredSameTypeReq(assocTypeDecl, inheritedType); } inheritedTypeDecls.erase(knownInherited); @@ -2751,7 +2882,8 @@ ConstraintResult GenericSignatureBuilder::addConformanceRequirement( continue; } - // FIXME: More typealiases + // Two typealiases that should be the same. + addInferredSameTypeReq(inheritedType, typealias); } inheritedTypeDecls.erase(knownInherited); @@ -2772,6 +2904,101 @@ ConstraintResult GenericSignatureBuilder::addConformanceRequirement( return ConstraintResult::Resolved; } +/// Perform typo correction on the given nested type, producing the +/// corrected name (if successful). +static AssociatedTypeDecl *typoCorrectNestedType( + GenericSignatureBuilder::PotentialArchetype *pa) { + StringRef name = pa->getNestedName().str(); + + // Look through all of the associated types of all of the protocols + // to which the parent conforms. + llvm::SmallVector bestMatches; + unsigned bestEditDistance = UINT_MAX; + unsigned maxScore = (name.size() + 1) / 3; + for (auto proto : pa->getParent()->getConformsTo()) { + for (auto member : getProtocolMembers(proto)) { + auto assocType = dyn_cast(member); + if (!assocType) + continue; + + unsigned dist = name.edit_distance(assocType->getName().str(), + /*AllowReplacements=*/true, + maxScore); + assert(dist > 0 && "nested type should have matched associated type"); + if (dist < bestEditDistance) { + maxScore = bestEditDistance = dist; + bestMatches.clear(); + } + if (dist == bestEditDistance) + bestMatches.push_back(assocType); + } + } + + // FIXME: Look through the superclass. + + // If we didn't find any matches at all, fail. + if (bestMatches.empty()) + return nullptr; + + // Make sure that we didn't find more than one match at the best + // edit distance. + for (auto other : llvm::makeArrayRef(bestMatches).slice(1)) { + if (other != bestMatches.front()) + return nullptr; + } + + return bestMatches.front(); +} + +ConstraintResult GenericSignatureBuilder::resolveUnresolvedType( + PotentialArchetype *pa, + bool allowTypoCorrection) { + // If something else resolved this type, we're done. + if (!pa->isUnresolved()) + return ConstraintResult::Resolved; + + // If the parent isn't resolved, we can't resolve this now. + auto parentPA = pa->getParent(); + if (parentPA->isUnresolved()) + return ConstraintResult::Unresolved; + + // Resolve this via its parent. + auto resolvedPA = + parentPA->getNestedArchetypeAnchor( + pa->getNestedName(), + *this, + ArchetypeResolutionKind::WellFormed); + if (resolvedPA) { + assert(!pa->isUnresolved() && "This type must have been resolved"); + return ConstraintResult::Resolved; + } + + // If we aren't allowed to perform typo correction, we can't resolve the + // constraint. + if (!allowTypoCorrection) + return ConstraintResult::Unresolved; + + // Try to typo correct to a nested type name. + auto correction = typoCorrectNestedType(pa); + if (!correction) { + pa->setInvalid(); + return ConstraintResult::Conflicting; + } + + // Note that this is being renamed. + pa->saveNameForRenaming(); + Impl->RenamedNestedTypes.push_back(pa); + + // Resolve the associated type and merge the potential archetypes. + auto replacement = pa->getParent()->getNestedType(correction, *this); + pa->resolveAssociatedType(correction, *this); + addSameTypeRequirement(pa, replacement, + RequirementSource::forNestedTypeNameMatch(pa), + UnresolvedHandlingKind::GenerateConstraints); + + return ConstraintResult::Resolved; +} + ConstraintResult GenericSignatureBuilder::addLayoutRequirementDirect( PotentialArchetype *PAT, LayoutConstraint Layout, @@ -2862,8 +3089,9 @@ void GenericSignatureBuilder::updateSuperclass( for (auto &nested : T->getNestedTypes()) { if (nested.second.empty()) continue; if (nested.second.front()->isUnresolved()) { - (void)T->getNestedArchetypeAnchor(nested.first, *this, - PotentialArchetype::NestedTypeUpdate::ResolveExisting); + (void)T->getNestedArchetypeAnchor( + nested.first, *this, + ArchetypeResolutionKind::AlreadyKnown); } } }; @@ -2877,7 +3105,7 @@ void GenericSignatureBuilder::updateSuperclass( // Presence of a superclass constraint implies a _Class layout // constraint. - auto layoutReqSource = source->viaSuperclass(*this, nullptr); + auto layoutReqSource = source->viaDerived(*this); addLayoutRequirementDirect(T, LayoutConstraint::getLayoutConstraint( superclass->getClassOrBoundGenericClass()->isObjC() @@ -3083,16 +3311,20 @@ GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes( if (T1 == T2) return ConstraintResult::Resolved; + unsigned nestingDepth1 = T1->getNestingDepth(); + unsigned nestingDepth2 = T2->getNestingDepth(); + // Decide which potential archetype is to be considered the representative. - // It doesn't specifically matter which we use, but it's a minor optimization - // to prefer the canonical type. - if (compareDependentTypes(&T2, &T1) < 0) { + // We prefer potential archetypes with lower nesting depths, because it + // prevents us from unnecessarily building deeply nested potential archetypes. + if (nestingDepth2 < nestingDepth1) { std::swap(T1, T2); std::swap(OrigT1, OrigT2); } // Merge the equivalence classes. auto equivClass = T1->getOrCreateEquivalenceClass(); + auto equivClass1Members = equivClass->members; auto equivClass2Members = T2->getEquivalenceClassMembers(); for (auto equiv : equivClass2Members) equivClass->members.push_back(equiv); @@ -3114,14 +3346,17 @@ GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes( } // Same-type-to-concrete requirements. - if (equivClass2 && equivClass2->concreteType) { - if (equivClass->concreteType) { + bool t1IsConcrete = !equivClass->concreteType.isNull(); + bool t2IsConcrete = equivClass2 && !equivClass2->concreteType.isNull(); + if (t2IsConcrete) { + if (t1IsConcrete) { (void)addSameTypeRequirement(equivClass->concreteType, equivClass2->concreteType, Source, UnresolvedHandlingKind::GenerateConstraints, - DiagnoseSameTypeConflict{Diags, Source, T1}); + SameTypeConflictCheckedLater()); } else { equivClass->concreteType = equivClass2->concreteType; + equivClass->invalidConcreteType = equivClass2->invalidConcreteType; } equivClass->concreteTypeConstraints.insert( @@ -3142,12 +3377,13 @@ GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes( else source2 = equivClass2->superclassConstraints.front().source; - (void)updateSuperclass(T1, equivClass2->superclass, source2); - + // Add the superclass constraints from the second equivalence class. equivClass->superclassConstraints.insert( equivClass->superclassConstraints.end(), equivClass2->superclassConstraints.begin(), equivClass2->superclassConstraints.end()); + + (void)updateSuperclass(T1, equivClass2->superclass, source2); } // Add all of the protocol conformance requirements of T2 to T1. @@ -3166,6 +3402,14 @@ GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes( auto dependentT1 = T1->getDependentType({ }, /*allowUnresolved=*/true); for (auto equivT2 : equivClass2Members) { for (auto T2Nested : equivT2->NestedTypes) { + // If T1 is concrete but T2 is not, concretize the nested types of T2. + if (t1IsConcrete && !t2IsConcrete) { + concretizeNestedTypeFromConcreteParent(T1, T2Nested.second.front(), + *this); + continue; + } + + // Otherwise, make the nested types equivalent. Type nestedT1 = DependentMemberType::get(dependentT1, T2Nested.first); if (isErrorResult( addSameTypeRequirement( @@ -3177,6 +3421,16 @@ GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes( } } + // If T2 is concrete but T1 was not, concretize the nested types of T1. + if (t2IsConcrete && !t1IsConcrete) { + for (auto equivT1 : equivClass1Members) { + for (auto T1Nested : equivT1->NestedTypes) { + concretizeNestedTypeFromConcreteParent(T2, T1Nested.second.front(), + *this); + } + } + } + return ConstraintResult::Resolved; } @@ -3196,56 +3450,26 @@ ConstraintResult GenericSignatureBuilder::addSameTypeRequirementToConcrete( if (equivClass->concreteType) { return addSameTypeRequirement(equivClass->concreteType, Concrete, Source, UnresolvedHandlingKind::GenerateConstraints, - DiagnoseSameTypeConflict{ Diags, Source, T}); + SameTypeConflictCheckedLater()); } // Record the requirement. equivClass->concreteType = Concrete; - // Make sure the concrete type fulfills the requirements on the archetype. - // FIXME: Move later... - DenseMap conformances; - CanType depTy = rep->getDependentType({ }, /*allowUnresolved=*/true) - ->getCanonicalType(); + // Make sure the concrete type fulfills the conformance requirements of + // this equivalence class. for (auto protocol : rep->getConformsTo()) { - auto conformance = - getLookupConformanceFn()(depTy, Concrete, - protocol->getDeclaredInterfaceType() - ->castTo()); - if (!conformance) { - if (!Concrete->hasError()) { - Diags.diagnose(Source->getLoc(), - diag::requires_generic_param_same_type_does_not_conform, - Concrete, protocol->getName()); - } + if (!resolveConcreteConformance(rep, protocol)) return ConstraintResult::Conflicting; - } - - conformances.insert({protocol, *conformance}); - - // Abstract conformances are acceptable for existential types. - assert(conformance->isConcrete() || Concrete->isExistentialType()); - - // Update the requirement source now that we know it's concrete. - // FIXME: Bad concrete source info. - auto concreteSource = Source->viaConcrete(*this, - conformance->isConcrete() - ? conformance->getConcrete() - : nullptr); - equivClass->conformsTo[protocol].push_back({T, protocol, concreteSource}); - ++NumConformanceConstraints; } // Eagerly resolve any existing nested types to their concrete forms (others // will be "concretized" as they are constructed, in getNestedType). for (auto equivT : rep->getEquivalenceClassMembers()) { for (auto nested : equivT->getNestedTypes()) { - concretizeNestedTypeFromConcreteParent( - equivT, Source, nested.second.front(), *this, - [&](ProtocolDecl *proto) -> ProtocolConformanceRef { - return conformances.find(proto)->second; - }); + concretizeNestedTypeFromConcreteParent(equivT, nested.second.front(), + *this); } } @@ -3329,17 +3553,6 @@ ConstraintResult GenericSignatureBuilder::addSameTypeRequirement( diagnoseMismatch); } -ConstraintResult GenericSignatureBuilder::addSameTypeRequirementDirect( - ResolvedType paOrT1, - ResolvedType paOrT2, - FloatingRequirementSource source) { - return addSameTypeRequirementDirect(paOrT1, paOrT2, source, - [&](Type type1, Type type2) { - Diags.diagnose(source.getLoc(), diag::requires_same_concrete_type, - type1, type2); - }); -} - ConstraintResult GenericSignatureBuilder::addSameTypeRequirementDirect( ResolvedType paOrT1, ResolvedType paOrT2, FloatingRequirementSource source, llvm::function_ref diagnoseMismatch) { @@ -3414,8 +3627,10 @@ ConstraintResult GenericSignatureBuilder::addInheritedRequirements( } // We are inferring requirements. - if (forInferred) - return FloatingRequirementSource::forInferred(typeRepr); + if (forInferred) { + return FloatingRequirementSource::forInferred(typeRepr, + /*quietly=*/false); + } // Explicit requirement. if (typeRepr) @@ -3475,7 +3690,7 @@ ConstraintResult GenericSignatureBuilder::addRequirement( ModuleDecl *inferForModule) { auto subst = [&](Type t) { if (subMap) - return t.subst(*subMap); + return t.subst(*subMap, SubstFlags::UseErrorType); return t; }; @@ -3578,9 +3793,11 @@ ConstraintResult GenericSignatureBuilder::addRequirement( if (inferForModule) { inferRequirements(*inferForModule, TypeLoc::withoutLoc(firstType), - FloatingRequirementSource::forInferred(nullptr)); + FloatingRequirementSource::forInferred( + nullptr, /*quietly=*/false)); inferRequirements(*inferForModule, TypeLoc::withoutLoc(secondType), - FloatingRequirementSource::forInferred(nullptr)); + FloatingRequirementSource::forInferred( + nullptr, /*quietly=*/false)); } return addTypeRequirement(firstType, secondType, source, @@ -3594,7 +3811,8 @@ ConstraintResult GenericSignatureBuilder::addRequirement( if (inferForModule) { inferRequirements(*inferForModule, TypeLoc::withoutLoc(firstType), - FloatingRequirementSource::forInferred(nullptr)); + FloatingRequirementSource::forInferred( + nullptr, /*quietly=*/false)); } return addLayoutRequirement(firstType, req.getLayoutConstraint(), source, @@ -3609,9 +3827,11 @@ ConstraintResult GenericSignatureBuilder::addRequirement( if (inferForModule) { inferRequirements(*inferForModule, TypeLoc::withoutLoc(firstType), - FloatingRequirementSource::forInferred(nullptr)); + FloatingRequirementSource::forInferred( + nullptr, /*quietly=*/false)); inferRequirements(*inferForModule, TypeLoc::withoutLoc(secondType), - FloatingRequirementSource::forInferred(nullptr)); + FloatingRequirementSource::forInferred( + nullptr, /*quietly=*/false)); } return addSameTypeRequirement( @@ -3685,60 +3905,10 @@ void GenericSignatureBuilder::inferRequirements( for (auto P : *params) { inferRequirements(module, P->getTypeLoc(), FloatingRequirementSource::forInferred( - P->getTypeLoc().getTypeRepr())); + P->getTypeLoc().getTypeRepr(), /*quietly=*/false)); } } -/// Perform typo correction on the given nested type, producing the -/// corrected name (if successful). -static Identifier typoCorrectNestedType( - GenericSignatureBuilder::PotentialArchetype *pa) { - StringRef name = pa->getNestedName().str(); - - // Look through all of the associated types of all of the protocols - // to which the parent conforms. - llvm::SmallVector bestMatches; - unsigned bestEditDistance = 0; - unsigned maxScore = (name.size() + 1) / 3; - for (auto proto : pa->getParent()->getConformsTo()) { - for (auto member : getProtocolMembers(proto)) { - auto assocType = dyn_cast(member); - if (!assocType) - continue; - - unsigned dist = name.edit_distance(assocType->getName().str(), - /*AllowReplacements=*/true, - maxScore); - assert(dist > 0 && "nested type should have matched associated type"); - if (bestEditDistance == 0 || dist == bestEditDistance) { - bestEditDistance = dist; - maxScore = bestEditDistance; - bestMatches.push_back(assocType->getName()); - } else if (dist < bestEditDistance) { - bestEditDistance = dist; - maxScore = bestEditDistance; - bestMatches.clear(); - bestMatches.push_back(assocType->getName()); - } - } - } - - // FIXME: Look through the superclass. - - // If we didn't find any matches at all, fail. - if (bestMatches.empty()) - return Identifier(); - - // Make sure that we didn't find more than one match at the best - // edit distance. - for (auto other : llvm::makeArrayRef(bestMatches).slice(1)) { - if (other != bestMatches.front()) - return Identifier(); - } - - return bestMatches.front(); -} - namespace swift { template bool operator<(const Constraint &lhs, const Constraint &rhs) { @@ -3793,8 +3963,11 @@ namespace { // We prefer constraints rooted at inferred requirements to ones rooted // on explicit requirements, because the former won't be diagnosed // directly. - bool thisIsInferred = constraint.source->isInferredRequirement(); - bool representativeIsInferred = representativeConstraint->source->isInferredRequirement(); + bool thisIsInferred = constraint.source->isInferredRequirement( + /*includeQuietInferred=*/false); + bool representativeIsInferred = + representativeConstraint->source->isInferredRequirement( + /*includeQuietInferred=*/false); if (thisIsInferred != representativeIsInferred) { if (thisIsInferred) representativeConstraint = constraint; @@ -4044,33 +4217,6 @@ GenericSignatureBuilder::finalize(SourceLoc loc, } } } - - // If any nested types remain unresolved, produce diagnostics. - if (Impl->NumUnresolvedNestedTypes > 0) { - visitPotentialArchetypes([&](PotentialArchetype *pa) { - // We only care about nested types that haven't been resolved. - if (!pa->isUnresolved()) return; - - // Try to typo correct to a nested type name. - Identifier correction = typoCorrectNestedType(pa); - if (correction.empty()) { - pa->setInvalid(); - return; - } - - // Note that this is being renamed. - pa->saveNameForRenaming(); - Impl->RenamedNestedTypes.push_back(pa); - - // Resolve the associated type and merge the potential archetypes. - auto replacement = pa->getParent()->getNestedType(correction, *this); - pa->resolveAssociatedType(replacement->getResolvedAssociatedType(), - *this); - addSameTypeRequirement(pa, replacement, - RequirementSource::forNestedTypeNameMatch(pa), - UnresolvedHandlingKind::GenerateConstraints); - }); - } } bool GenericSignatureBuilder::diagnoseRemainingRenames( @@ -4102,35 +4248,45 @@ static GenericSignatureBuilder::UnresolvedType asUnresolvedType( void GenericSignatureBuilder::processDelayedRequirements() { bool anySolved = !Impl->DelayedRequirements.empty(); + bool allowTypoCorrection = false; while (anySolved) { // Steal the delayed requirements so we can reprocess them. anySolved = false; auto delayed = std::move(Impl->DelayedRequirements); Impl->DelayedRequirements.clear(); + // Whether we saw any unresolve type constraints that we couldn't + // resolve. + bool hasUnresolvedUnresolvedTypes = false; + // Process delayed requirements. for (const auto &req : delayed) { // Reprocess the delayed requirement. ConstraintResult reqResult; switch (req.kind) { - case RequirementKind::Conformance: - case RequirementKind::Superclass: + case DelayedRequirement::Type: reqResult = addTypeRequirement( req.lhs, asUnresolvedType(req.rhs), req.source, UnresolvedHandlingKind::ReturnUnresolved); break; - case RequirementKind::Layout: + case DelayedRequirement::Layout: reqResult = addLayoutRequirement( req.lhs, req.rhs.get(), req.source, UnresolvedHandlingKind::ReturnUnresolved); break; - case RequirementKind::SameType: + case DelayedRequirement::SameType: reqResult = addSameTypeRequirement( req.lhs, asUnresolvedType(req.rhs), req.source, UnresolvedHandlingKind::ReturnUnresolved); break; + + case DelayedRequirement::Unresolved: + reqResult = resolveUnresolvedType( + req.lhs.get(), + allowTypoCorrection); + break; } // Update our state based on what happened. @@ -4147,9 +4303,19 @@ void GenericSignatureBuilder::processDelayedRequirements() { case ConstraintResult::Unresolved: // Add the requirement back. Impl->DelayedRequirements.push_back(req); + + if (req.kind == DelayedRequirement::Unresolved) + hasUnresolvedUnresolvedTypes = true; break; } } + + // If we didn't solve anything, but we did see some unresolved types, + // try again with typo correction enabled. + if (!anySolved && hasUnresolvedUnresolvedTypes && !allowTypoCorrection) { + allowTypoCorrection = true; + anySolved = true; + } } } @@ -4324,7 +4490,8 @@ Constraint GenericSignatureBuilder::checkConstraintList( // If this requirement is not derived or inferred (but has a useful // location) complain that it is redundant. if (!constraint.source->isDerivedRequirement() && - !constraint.source->isInferredRequirement() && + !constraint.source->isInferredRequirement( + /*includeQuietInferred=*/true) && constraint.source->getLoc().isValid()) { Diags.diagnose(constraint.source->getLoc(), redundancyDiag, @@ -4447,7 +4614,12 @@ static PotentialArchetype *getLocalAnchor(PotentialArchetype *pa, if (!parent) return pa; auto parentAnchor = getLocalAnchor(parent, builder); - return parentAnchor->getNestedArchetypeAnchor(pa->getNestedName(), builder); + if (!parentAnchor) return pa; + auto localAnchor = + parentAnchor->getNestedArchetypeAnchor( + pa->getNestedName(), builder, + ArchetypeResolutionKind::CompleteWellFormed); + return localAnchor ? localAnchor : pa; } /// Computes the ordered set of archetype anchors required to form a minimum @@ -4556,8 +4728,12 @@ namespace { return lhs.target < rhs.target; // Prefer non-inferred requirement sources. - bool lhsIsInferred = lhs.constraint.source->isInferredRequirement(); - bool rhsIsInferred = rhs.constraint.source->isInferredRequirement(); + bool lhsIsInferred = + lhs.constraint.source->isInferredRequirement( + /*includeQuietInferred=*/false); + bool rhsIsInferred = + rhs.constraint.source->isInferredRequirement( + /*includeQuietInferred=*/false); if (lhsIsInferred != rhsIsInferred) return rhsIsInferred;; @@ -4620,7 +4796,8 @@ void GenericSignatureBuilder::checkSameTypeConstraints( // If the source/destination are identical, complain. if (constraint.archetype == constraint.value) { if (!constraint.source->isDerivedRequirement() && - !constraint.source->isInferredRequirement() && + !constraint.source->isInferredRequirement( + /*includeQuietInferred=*/true) && constraint.source->getLoc().isValid()) { Diags.diagnose(constraint.source->getLoc(), diag::redundant_same_type_constraint, @@ -4722,7 +4899,8 @@ void GenericSignatureBuilder::checkSameTypeConstraints( return true; // If the constraint source is inferred, don't diagnose it. - if (lhs.constraint.source->isInferredRequirement()) + if (lhs.constraint.source->isInferredRequirement( + /*includeQuietInferred=*/true)) return true; Diags.diagnose(lhs.constraint.source->getLoc(), @@ -4754,7 +4932,8 @@ void GenericSignatureBuilder::checkSameTypeConstraints( // not part of the spanning tree. if (connected[edge.source] && connected[edge.target]) { if (edge.constraint.source->getLoc().isValid() && - !edge.constraint.source->isInferredRequirement() && + !edge.constraint.source->isInferredRequirement( + /*includeQuietInferred=*/true) && firstEdge.constraint.source->getLoc().isValid()) { Diags.diagnose(edge.constraint.source->getLoc(), diag::redundant_same_type_constraint, @@ -4811,8 +4990,8 @@ void GenericSignatureBuilder::checkConcreteTypeConstraints( checkConstraintList( genericParams, equivClass->concreteTypeConstraints, - [](const ConcreteConstraint &constraint) { - return true; + [&](const ConcreteConstraint &constraint) { + return constraint.value->isEqual(equivClass->concreteType); }, [&](Type concreteType) { // If the concrete type is equivalent, the constraint is redundant. @@ -4821,10 +5000,14 @@ void GenericSignatureBuilder::checkConcreteTypeConstraints( if (concreteType->isEqual(equivClass->concreteType)) return ConstraintRelation::Redundant; - // Call this unrelated. - return ConstraintRelation::Unrelated; + // If either has a type parameter, call them unrelated. + if (concreteType->hasTypeParameter() || + equivClass->concreteType->hasTypeParameter()) + return ConstraintRelation::Unrelated; + + return ConstraintRelation::Conflicting; }, - None, + diag::same_type_conflict, diag::redundant_same_type_to_concrete, diag::same_type_redundancy_here); @@ -5043,8 +5226,11 @@ void GenericSignatureBuilder::enumerateRequirements(llvm::function_ref< auto equivClass = rep->getOrCreateEquivalenceClass(); // If we didn't compute the derived same-type components yet, do so now. - if (equivClass->derivedSameTypeComponents.empty()) + if (equivClass->derivedSameTypeComponents.empty()) { checkSameTypeConstraints(Impl->GenericParams, rep); + rep = archetype->getRepresentative(); + equivClass = rep->getOrCreateEquivalenceClass(); + } assert(!equivClass->derivedSameTypeComponents.empty() && "Didn't compute derived same-type components?"); @@ -5071,8 +5257,9 @@ void GenericSignatureBuilder::enumerateRequirements(llvm::function_ref< ? knownAnchor->concreteTypeSource : RequirementSource::forAbstract(archetype); - // Drop recursive concrete-type constraints. - if (equivClass->recursiveConcreteType) + // Drop recursive and invalid concrete-type constraints. + if (equivClass->recursiveConcreteType || + equivClass->invalidConcreteType) continue; f(RequirementKind::SameType, archetype, concreteType, source); @@ -5266,14 +5453,8 @@ static void collectRequirements(GenericSignatureBuilder &builder, // Drop requirements involving concrete types containing // unresolved associated types. - if (repTy.findIf([](Type t) -> bool { - if (auto *depTy = dyn_cast(t.getPointer())) - if (depTy->getAssocType() == nullptr) - return true; - return false; - })) { + if (repTy->findUnresolvedDependentMemberType()) return; - } } else if (auto layoutConstraint = type.dyn_cast()) { requirements.push_back(Requirement(kind, depTy, layoutConstraint)); return; diff --git a/lib/AST/Identifier.cpp b/lib/AST/Identifier.cpp index 7d7df375169..1fae6e51794 100644 --- a/lib/AST/Identifier.cpp +++ b/lib/AST/Identifier.cpp @@ -27,9 +27,8 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, Identifier I) { return OS << I.get(); } -raw_ostream &llvm::operator<<(raw_ostream &OS, DeclBaseName I) { - // TODO: Handle special names - return OS << I.getIdentifier(); +raw_ostream &llvm::operator<<(raw_ostream &OS, DeclBaseName D) { + return OS << D.userFacingName(); } raw_ostream &llvm::operator<<(raw_ostream &OS, DeclName I) { diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 09ed0e2db34..ef44b95d50c 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -346,7 +346,7 @@ void SourceLookupCache::invalidate() { ModuleDecl::ModuleDecl(Identifier name, ASTContext &ctx) : TypeDecl(DeclKind::Module, &ctx, name, SourceLoc(), { }), DeclContext(DeclContextKind::Module, nullptr), - Flags({0, 0, 0}), DSOHandle(nullptr) { + Flags({0, 0, 0}) { ctx.addDestructorCleanup(*this); setImplicit(); setInterfaceType(ModuleType::get(this)); diff --git a/lib/AST/NameLookupImpl.h b/lib/AST/NameLookupImpl.h index 22da51be1c9..0d8ff5a4e62 100644 --- a/lib/AST/NameLookupImpl.h +++ b/lib/AST/NameLookupImpl.h @@ -151,10 +151,6 @@ private: visit(S->getBody()); } - void visitIfConfigStmt(IfConfigStmt * S) { - // Active members are attached to the enclosing declaration, so there's no - // need to walk anything within. - } void visitWhileStmt(WhileStmt *S) { if (!isReferencePointInRange(S->getSourceRange())) return; diff --git a/lib/AST/SourceEntityWalker.cpp b/lib/AST/SourceEntityWalker.cpp index 7b459515af0..7b0471014f3 100644 --- a/lib/AST/SourceEntityWalker.cpp +++ b/lib/AST/SourceEntityWalker.cpp @@ -95,9 +95,8 @@ bool SemaAnnotator::walkToDeclPre(Decl *D) { bool IsExtension = false; if (auto *VD = dyn_cast(D)) { - // TODO: Handle special names if (VD->hasName() && !VD->isImplicit()) - NameLen = VD->getBaseName().getIdentifier().getLength(); + NameLen = VD->getBaseName().userFacingName().size(); auto ReportParamList = [&](ParameterList *PL) { for (auto *PD : *PL) { @@ -142,6 +141,15 @@ bool SemaAnnotator::walkToDeclPre(Decl *D) { if (Loc.isValid()) NameLen = PrecD->getName().getLength(); + } else if (auto *ICD = dyn_cast(D)) { + if (SEWalker.shouldWalkInactiveConfigRegion()) { + for (auto Clause : ICD->getClauses()) { + for (auto Member : Clause.Elements) { + Member.walk(*this); + } + } + return false; + } } else { return true; } @@ -199,17 +207,6 @@ bool SemaAnnotator::walkToDeclPost(Decl *D) { std::pair SemaAnnotator::walkToStmtPre(Stmt *S) { bool TraverseChildren = SEWalker.walkToStmtPre(S); if (TraverseChildren) { - if (SEWalker.shouldWalkInactiveConfigRegion()) { - if (auto *ICS = dyn_cast(S)) { - TraverseChildren = false; - for (auto Clause : ICS->getClauses()) { - for (auto Member : Clause.Elements) { - Member.walk(*this); - } - } - } - } - if (auto *DeferS = dyn_cast(S)) { if (auto *FD = DeferS->getTempDecl()) { auto *RetS = FD->getBody()->walk(*this); diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 2b7d11f5a8e..18ce6a4220d 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -412,15 +412,22 @@ CaseStmt *CaseStmt::create(ASTContext &C, SourceLoc CaseLoc, SwitchStmt *SwitchStmt::create(LabeledStmtInfo LabelInfo, SourceLoc SwitchLoc, Expr *SubjectExpr, SourceLoc LBraceLoc, - ArrayRef Cases, + ArrayRef Cases, SourceLoc RBraceLoc, ASTContext &C) { - void *p = C.Allocate(totalSizeToAlloc(Cases.size()), +#ifndef NDEBUG + for (auto N : Cases) + assert((N.is() && isa(N.get())) || + (N.is() && isa(N.get()))); +#endif + + void *p = C.Allocate(totalSizeToAlloc(Cases.size()), alignof(SwitchStmt)); SwitchStmt *theSwitch = ::new (p) SwitchStmt(LabelInfo, SwitchLoc, SubjectExpr, LBraceLoc, Cases.size(), RBraceLoc); + std::uninitialized_copy(Cases.begin(), Cases.end(), - theSwitch->getTrailingObjects()); + theSwitch->getTrailingObjects()); return theSwitch; } diff --git a/lib/AST/SubstitutionMap.cpp b/lib/AST/SubstitutionMap.cpp index da9b7bb6fb3..f4351c0c378 100644 --- a/lib/AST/SubstitutionMap.cpp +++ b/lib/AST/SubstitutionMap.cpp @@ -223,7 +223,8 @@ SubstitutionMap::lookupConformance(CanType type, ProtocolDecl *proto) const { auto *M = proto->getParentModule(); auto substType = type.subst(*this); if (substType && - !substType->is() && + (!substType->is() || + substType->castTo()->getSuperclass()) && !substType->isTypeParameter() && !substType->isExistentialType()) { auto lazyResolver = M->getASTContext().getLazyResolver(); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index e101f407d2f..32dab3c07d3 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -709,13 +709,13 @@ Type TypeBase::replaceCovariantResultType(Type newResultType, return FunctionType::get(inputType, resultType, fnType->getExtInfo()); } -SmallVector +SmallVector swift::decomposeArgType(Type type, ArrayRef argumentLabels) { - SmallVector result; + SmallVector result; switch (type->getKind()) { case TypeKind::Tuple: { auto tupleTy = cast(type.getPointer()); - + // If we have one argument label but a tuple argument with > 1 element, // put the whole tuple into the argument. // FIXME: This horribleness is due to the mis-modeling of arguments as @@ -724,45 +724,38 @@ swift::decomposeArgType(Type type, ArrayRef argumentLabels) { // Break out to do the default thing below. break; } - + for (auto i : range(0, tupleTy->getNumElements())) { const auto &elt = tupleTy->getElement(i); - assert(elt.getParameterFlags().isNone() && + assert((elt.getParameterFlags().isNone() || + elt.getParameterFlags().isInOut()) && "Vararg, autoclosure, or escaping argument tuple" "doesn't make sense"); - CallArgParam argParam; - argParam.Ty = elt.getType(); - argParam.Label = argumentLabels[i]; - result.push_back(argParam); + result.push_back(AnyFunctionType::Param(elt.getType(), + argumentLabels[i], {})); } return result; } - + case TypeKind::Paren: { - CallArgParam argParam; - argParam.Ty = cast(type.getPointer())->getUnderlyingType(); - result.push_back(argParam); + auto ty = cast(type.getPointer())->getUnderlyingType(); + result.push_back(AnyFunctionType::Param(ty, Identifier(), {})); return result; } - + default: // Default behavior below; inject the argument as the sole parameter. break; } - + // Just inject this parameter. - assert(result.empty()); - CallArgParam argParam; - argParam.Ty = type; - assert(argumentLabels.size() == 1); - argParam.Label = argumentLabels[0]; - result.push_back(argParam); + assert(result.empty() && (argumentLabels.size() == 1)); + result.push_back(AnyFunctionType::Param(type, argumentLabels[0], {})); return result; } -SmallVector -swift::decomposeParamType(Type type, const ValueDecl *paramOwner, - unsigned level) { +void swift::computeDefaultMap(Type type, const ValueDecl *paramOwner, + unsigned level, SmallVectorImpl &outDefaultMap) { // Find the corresponding parameter list. const ParameterList *paramList = nullptr; if (paramOwner) { @@ -774,61 +767,44 @@ swift::decomposeParamType(Type type, const ValueDecl *paramOwner, paramList = subscript->getIndices(); } } - - SmallVector result; + switch (type->getKind()) { case TypeKind::Tuple: { auto tupleTy = cast(type.getPointer()); - + // FIXME: In the weird case where we have a tuple type that should // be wrapped in a ParenType but isn't, just... forget it happened. if (paramList && tupleTy->getNumElements() != paramList->size() && paramList->size() == 1) paramList = nullptr; - + for (auto i : range(0, tupleTy->getNumElements())) { - const auto &elt = tupleTy->getElement(i); - - CallArgParam argParam; - argParam.Ty = elt.isVararg() ? elt.getVarargBaseTy() : elt.getType(); - argParam.Label = elt.getName(); - argParam.HasDefaultArgument = - paramList && paramList->get(i)->isDefaultArgument(); - argParam.parameterFlags = elt.getParameterFlags(); - result.push_back(argParam); + outDefaultMap.push_back(paramList && paramList->get(i)->isDefaultArgument()); } break; } - + case TypeKind::Paren: { - CallArgParam argParam; - argParam.Ty = cast(type.getPointer())->getUnderlyingType(); - argParam.HasDefaultArgument = - paramList && paramList->get(0)->isDefaultArgument(); - result.push_back(argParam); + outDefaultMap.push_back(paramList && paramList->get(0)->isDefaultArgument()); break; } - + default: { - CallArgParam argParam; - argParam.Ty = type; - result.push_back(argParam); + outDefaultMap.push_back(false); break; } } - - return result; } /// Turn a param list into a symbolic and printable representation that does not /// include the types, something like (_:, b:, c:) -std::string swift::getParamListAsString(ArrayRef params) { +std::string swift::getParamListAsString(ArrayRef params) { std::string result = "("; interleave(params, - [&](const CallArgParam ¶m) { - if (param.hasLabel()) - result += param.Label.str(); + [&](const AnyFunctionType::Param ¶m) { + if (!param.getLabel().empty()) + result += param.getLabel().str(); else result += "_"; result += ":"; @@ -1131,7 +1107,9 @@ CanType TypeBase::getCanonicalType() { // Transform the input and result types. auto &ctx = function->getInput()->getASTContext(); auto &mod = *ctx.TheBuiltinModule; - auto inputTy = function->getInput()->getCanonicalType(sig, mod); + Type inputTy = function->getInput()->getCanonicalType(sig, mod); + if (!AnyFunctionType::isCanonicalFunctionInputType(inputTy)) + inputTy = ParenType::get(ctx, inputTy); auto resultTy = function->getResult()->getCanonicalType(sig, mod); Result = GenericFunctionType::get(sig, inputTy, resultTy, @@ -1148,6 +1126,10 @@ CanType TypeBase::getCanonicalType() { case TypeKind::Function: { FunctionType *FT = cast(this); Type In = FT->getInput()->getCanonicalType(); + if (!AnyFunctionType::isCanonicalFunctionInputType(In)) { + In = ParenType::get(In->getASTContext(), In); + assert(AnyFunctionType::isCanonicalFunctionInputType(In)); + } Type Out = FT->getResult()->getCanonicalType(); Result = FunctionType::get(In, Out, FT->getExtInfo()); break; @@ -2860,6 +2842,17 @@ Type ProtocolCompositionType::get(const ASTContext &C, return build(C, CanTypes, HasExplicitAnyObject); } +bool AnyFunctionType::isCanonicalFunctionInputType(Type input) { + // Canonically, we should have a tuple type or parenthesized type. + if (auto tupleTy = dyn_cast(input.getPointer())) + return tupleTy->isCanonical(); + if (auto parenTy = dyn_cast(input.getPointer())) + return parenTy->getUnderlyingType()->isCanonical(); + + // FIXME: Still required for the constraint solver. + return isa(input.getPointer()); +} + FunctionType * GenericFunctionType::substGenericArgs(SubstitutionList args) { return substGenericArgs(getGenericSignature()->getSubstitutionMap(args)); @@ -3156,6 +3149,24 @@ Type Type::substDependentTypesWithErrorTypes() const { SubstFlags::UseErrorType)); } +const DependentMemberType *TypeBase::findUnresolvedDependentMemberType() { + if (!hasTypeParameter()) return nullptr; + + const DependentMemberType *unresolvedDepMemTy = nullptr; + Type(this).findIf([&](Type type) -> bool { + if (auto depMemTy = type->getAs()) { + if (depMemTy->getAssocType() == nullptr) { + unresolvedDepMemTy = depMemTy; + return true; + } + } + return false; + }); + + return unresolvedDepMemTy; +} + + Type TypeBase::getSuperclassForDecl(const ClassDecl *baseClass) { Type t(this); while (t) { @@ -3623,6 +3634,9 @@ case TypeKind::Id: case TypeKind::NameAlias: { auto alias = cast(base); auto underlyingTy = Type(alias->getSinglyDesugaredType()); + if (!underlyingTy) + return Type(); + auto transformedTy = underlyingTy.transformRec(fn); if (!transformedTy) return Type(); diff --git a/lib/AST/TypeRepr.cpp b/lib/AST/TypeRepr.cpp index 8129e0eac94..b439a10466c 100644 --- a/lib/AST/TypeRepr.cpp +++ b/lib/AST/TypeRepr.cpp @@ -182,15 +182,16 @@ TypeRepr * CloneVisitor::visitImplicitlyUnwrappedOptionalTypeRepr( } TypeRepr *CloneVisitor::visitTupleTypeRepr(TupleTypeRepr *T) { - // FIXME: Avoid this stash vector. - SmallVector elements; + SmallVector elements; elements.reserve(T->getNumElements()); - for (auto *arg : T->getElements()) - elements.push_back(visit(arg)); - return TupleTypeRepr::create(Ctx, elements, T->getParens(), - T->getElementNames(), T->getElementNameLocs(), - T->getUnderscoreLocs(), - T->getEllipsisLoc(), T->getEllipsisIndex()); + for (auto arg : T->getElements()) { + arg.Type = visit(arg.Type); + elements.push_back(arg); + } + return TupleTypeRepr::create(Ctx, elements, + T->getParens(), + T->getEllipsisLoc(), + T->getEllipsisIndex()); } TypeRepr *CloneVisitor::visitCompositionTypeRepr(CompositionTypeRepr *T) { @@ -401,72 +402,41 @@ void ImplicitlyUnwrappedOptionalTypeRepr::printImpl(ASTPrinter &Printer, Printer << "!"; } -TupleTypeRepr::TupleTypeRepr(ArrayRef Elements, SourceRange Parens, - ArrayRef ElementNames, - ArrayRef ElementNameLocs, - ArrayRef underscoreLocs, +TupleTypeRepr::TupleTypeRepr(ArrayRef Elements, + SourceRange Parens, SourceLoc Ellipsis, unsigned EllipsisIdx) - : TypeRepr(TypeReprKind::Tuple), NumElements(Elements.size()), - Parens(Parens) { - - TupleTypeReprBits.NameStatus = ElementNames.empty() ? NotNamed - : underscoreLocs.empty() ? HasNames : HasLabels; - TupleTypeReprBits.HasEllipsis = Ellipsis.isValid(); + : TypeRepr(TypeReprKind::Tuple), Parens(Parens) { // Copy elements. std::uninitialized_copy(Elements.begin(), Elements.end(), - getTrailingObjects()); - - // Copy elements names. - std::uninitialized_copy(ElementNames.begin(), ElementNames.end(), - getTrailingObjects()); - - // Copy elements names locations. - std::uninitialized_copy(ElementNameLocs.begin(), ElementNameLocs.end(), - getTrailingObjects()); - - // Copy elements underscore locations. - std::uninitialized_copy(underscoreLocs.begin(), underscoreLocs.end(), - getTrailingObjects() + - ElementNameLocs.size()); + getTrailingObjects()); + TupleTypeReprBits.HasEllipsis = Ellipsis.isValid(); + TupleTypeReprBits.NumElements = Elements.size(); // Set ellipsis location and index. - if (Ellipsis.isValid()) + if (Ellipsis.isValid()) { getTrailingObjects()[0] = {Ellipsis, EllipsisIdx}; + } } TupleTypeRepr *TupleTypeRepr::create(const ASTContext &C, - ArrayRef Elements, + ArrayRef Elements, SourceRange Parens, - ArrayRef ElementNames, - ArrayRef ElementNameLocs, - ArrayRef underscoreLocs, SourceLoc Ellipsis, unsigned EllipsisIdx) { - assert(ElementNames.size() == 0 || - ElementNames.size() == Elements.size()); - assert(ElementNameLocs.size() == ElementNames.size()); - assert(underscoreLocs.size() == 0 || - underscoreLocs.size() == Elements.size()); assert(Ellipsis.isValid() ? EllipsisIdx < Elements.size() : EllipsisIdx == Elements.size()); size_t size = - totalSizeToAlloc( - Elements.size(), - ElementNames.size(), - ElementNameLocs.size() + underscoreLocs.size(), - Ellipsis.isValid() ? 1 : 0); + totalSizeToAlloc( + Elements.size(), Ellipsis.isValid() ? 1 : 0); void *mem = C.Allocate(size, alignof(TupleTypeRepr)); - return new (mem) TupleTypeRepr(Elements, Parens, ElementNames, - ElementNameLocs, underscoreLocs, + return new (mem) TupleTypeRepr(Elements, Parens, Ellipsis, EllipsisIdx); } - TupleTypeRepr *TupleTypeRepr::createEmpty(const ASTContext &C, SourceRange Parens) { return create(C, {}, Parens, - /*ElementNames=*/{}, /*ElementNameLocs=*/{}, /*underscoreLocs=*/{}, /*Ellipsis=*/SourceLoc(), /*EllipsisIdx=*/0); } @@ -503,7 +473,7 @@ void TupleTypeRepr::printImpl(ASTPrinter &Printer, Printer << "("; - for (unsigned i = 0, e = NumElements; i != e; ++i) { + for (unsigned i = 0, e = TupleTypeReprBits.NumElements; i != e; ++i) { if (i) Printer << ", "; Printer.callPrintStructurePre(PrintStructureKind::TupleElement); auto name = getElementName(i); @@ -522,7 +492,7 @@ void TupleTypeRepr::printImpl(ASTPrinter &Printer, Printer << ": "; } } - printTypeRepr(getElement(i), Printer, Opts); + printTypeRepr(getElementType(i), Printer, Opts); Printer.printStructurePost(PrintStructureKind::TupleElement); if (hasEllipsis() && getEllipsisIndex() == i) diff --git a/lib/AST/TypeWalker.cpp b/lib/AST/TypeWalker.cpp index 3557667ee79..70e1061dc44 100644 --- a/lib/AST/TypeWalker.cpp +++ b/lib/AST/TypeWalker.cpp @@ -73,8 +73,11 @@ class Traversal : public TypeVisitor } bool visitAnyFunctionType(AnyFunctionType *ty) { - if (doIt(ty->getInput())) - return true; + for (const auto ¶m : ty->getParams()) { + if (doIt(param.getType())) + return true; + } + return doIt(ty->getResult()); } diff --git a/lib/AST/USRGeneration.cpp b/lib/AST/USRGeneration.cpp index 174464d0fbc..a5365da184e 100644 --- a/lib/AST/USRGeneration.cpp +++ b/lib/AST/USRGeneration.cpp @@ -215,7 +215,8 @@ bool ide::printDeclUSR(const ValueDecl *D, raw_ostream &OS) { auto &Importer = *D->getASTContext().getClangModuleLoader(); auto ClangMacroInfo = ClangN.getAsMacro(); - bool Ignore = clang::index::generateUSRForMacro(D->getNameStr(), + bool Ignore = clang::index::generateUSRForMacro( + D->getBaseName().getIdentifier().str(), ClangMacroInfo->getDefinitionLoc(), Importer.getClangASTContext().getSourceManager(), Buf); if (!Ignore) diff --git a/lib/Basic/LangOptions.cpp b/lib/Basic/LangOptions.cpp index d648b4abf67..6906b011585 100644 --- a/lib/Basic/LangOptions.cpp +++ b/lib/Basic/LangOptions.cpp @@ -36,6 +36,7 @@ static const StringRef SupportedConditionalCompilationOSs[] = { "Windows", "Android", "PS4", + "Cygwin", }; static const StringRef SupportedConditionalCompilationArches[] = { @@ -157,6 +158,8 @@ std::pair LangOptions::setTarget(llvm::Triple triple) { addPlatformConditionValue(PlatformConditionKind::OS, "FreeBSD"); else if (triple.isOSWindows()) addPlatformConditionValue(PlatformConditionKind::OS, "Windows"); + else if (triple.isWindowsCygwinEnvironment()) + addPlatformConditionValue(PlatformConditionKind::OS, "Cygwin"); else if (triple.isPS4()) addPlatformConditionValue(PlatformConditionKind::OS, "PS4"); else diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index ff9b12de77e..09182470b03 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -562,24 +562,6 @@ getNormalInvocationArguments(std::vector &invocationArgStrs, } } - if (triple.isOSDarwin()) { - std::string minVersionBuf; - llvm::raw_string_ostream minVersionOpt{minVersionBuf}; - minVersionOpt << getMinVersionOptNameForDarwinTriple(triple); - - unsigned major, minor, micro; - if (triple.isiOS()) { - triple.getiOSVersion(major, minor, micro); - } else if (triple.isWatchOS()) { - triple.getWatchOSVersion(major, minor, micro); - } else { - assert(triple.isMacOSX()); - triple.getMacOSXVersion(major, minor, micro); - } - minVersionOpt << clang::VersionTuple(major, minor, micro); - invocationArgStrs.push_back(std::move(minVersionOpt.str())); - } - if (searchPathOpts.SDKPath.empty()) { invocationArgStrs.push_back("-Xclang"); invocationArgStrs.push_back("-nostdsysteminc"); @@ -619,6 +601,23 @@ getNormalInvocationArguments(std::vector &invocationArgStrs, "-Xclang", "-fmodule-format=obj", }); } + + // Enable API notes alongside headers/in frameworks. + invocationArgStrs.push_back("-fapinotes-modules"); + + // Add API notes paths. + for (const auto &searchPath : searchPathOpts.ImportSearchPaths) { + invocationArgStrs.push_back("-iapinotes-modules"); + invocationArgStrs.push_back(searchPath); + } + invocationArgStrs.push_back("-iapinotes-modules"); + invocationArgStrs.push_back(searchPathOpts.RuntimeLibraryImportPath); + + // Map the Swift major version into the API notes version for Swift. This + // has the effect of allowing API notes to effect changes only on Swift + // major versions, not minor versions. + invocationArgStrs.push_back("-fapinotes-swift-version=" + + llvm::itostr(languageVersion[0])); } static void @@ -647,6 +646,24 @@ addCommonInvocationArguments(std::vector &invocationArgStrs, invocationArgStrs.push_back("-target"); invocationArgStrs.push_back(triple.str()); + if (triple.isOSDarwin()) { + std::string minVersionBuf; + llvm::raw_string_ostream minVersionOpt{minVersionBuf}; + minVersionOpt << getMinVersionOptNameForDarwinTriple(triple); + + unsigned major, minor, micro; + if (triple.isiOS()) { + triple.getiOSVersion(major, minor, micro); + } else if (triple.isWatchOS()) { + triple.getWatchOSVersion(major, minor, micro); + } else { + assert(triple.isMacOSX()); + triple.getMacOSXVersion(major, minor, micro); + } + minVersionOpt << clang::VersionTuple(major, minor, micro); + invocationArgStrs.push_back(std::move(minVersionOpt.str())); + } + invocationArgStrs.push_back(ImporterImpl::moduleImportBufferName); if (ctx.LangOpts.EnableAppExtensionRestrictions) { @@ -690,23 +707,6 @@ addCommonInvocationArguments(std::vector &invocationArgStrs, for (auto extraArg : importerOpts.ExtraArgs) { invocationArgStrs.push_back(extraArg); } - - // Enable API notes alongside headers/in frameworks. - invocationArgStrs.push_back("-fapinotes-modules"); - - // Add API notes paths. - for (const auto &searchPath : searchPathOpts.ImportSearchPaths) { - invocationArgStrs.push_back("-iapinotes-modules"); - invocationArgStrs.push_back(searchPath); - } - invocationArgStrs.push_back("-iapinotes-modules"); - invocationArgStrs.push_back(searchPathOpts.RuntimeLibraryImportPath); - - // Map the Swift major version into the API notes version for Swift. This - // has the effect of allowing API notes to effect changes only on Swift - // major versions, not minor versions. - invocationArgStrs.push_back("-fapinotes-swift-version=" + - llvm::itostr(ctx.LangOpts.EffectiveLanguageVersion[0])); } bool ClangImporter::canReadPCH(StringRef PCHFilename) { @@ -2025,7 +2025,9 @@ class DarwinBlacklistDeclConsumer : public swift::VisibleDeclConsumer { return false; if (clangModule->Name == "MacTypes") { - return llvm::StringSwitch(VD->getNameStr()) + if (!VD->hasName() || VD->getBaseName().isSpecial()) + return true; + return llvm::StringSwitch(VD->getBaseName().getIdentifier().str()) .Cases("OSErr", "OSStatus", "OptionBits", false) .Cases("FourCharCode", "OSType", false) .Case("Boolean", false) @@ -2271,7 +2273,14 @@ void ClangModuleUnit::getTopLevelDecls(SmallVectorImpl &results) const { owner.importDecl(decl, owner.CurrentVersion); if (!importedDecl) continue; - auto ext = dyn_cast(importedDecl->getDeclContext()); + // Find the enclosing extension, if there is one. + ExtensionDecl *ext = nullptr; + for (auto importedDC = importedDecl->getDeclContext(); + !importedDC->isModuleContext(); + importedDC = importedDC->getParent()) { + ext = dyn_cast(importedDC); + if (ext) break; + } if (!ext) continue; if (knownExtensions.insert(ext).second) diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 40d4679aee2..3a01cfc948b 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -128,7 +128,7 @@ createVarWithPattern(ASTContext &cxt, DeclContext *dc, Identifier name, Type ty, /*IsStatic*/false, /*IsLet*/isLet, /*IsCaptureList*/false, - SourceLoc(), name, ty, dc); + SourceLoc(), name, dc->mapTypeIntoContext(ty), dc); if (isImplicit) var->setImplicit(); var->setInterfaceType(ty); @@ -3167,7 +3167,7 @@ namespace { /*IsStatic*/false, /*IsLet*/ false, /*IsCaptureList*/false, Impl.importSourceLoc(decl->getLocStart()), - name, type, dc); + name, dc->mapTypeIntoContext(type), dc); result->setInterfaceType(type); // If this is a compatibility stub, mark is as such. @@ -3388,7 +3388,7 @@ namespace { /*IsStatic*/ false, /*IsLet*/ false, /*IsCaptureList*/false, Impl.importSourceLoc(decl->getLocation()), - name, type, dc); + name, dc->mapTypeIntoContext(type), dc); result->setInterfaceType(type); // Handle attributes. @@ -3464,7 +3464,7 @@ namespace { /*IsLet*/Impl.shouldImportGlobalAsLet(decl->getType()), /*IsCaptureList*/false, Impl.importSourceLoc(decl->getLocation()), - name, type, dc); + name, dc->mapTypeIntoContext(type), dc); result->setInterfaceType(type); // If imported as member, the member should be final. @@ -4324,7 +4324,6 @@ namespace { isInSystemModule(dc), /*isFullyBridgeable*/false); if (superclassType) { - superclassType = result->mapTypeOutOfContext(superclassType); assert(superclassType->is() || superclassType->is()); inheritedTypes.push_back(TypeLoc::withoutLoc(superclassType)); @@ -4539,8 +4538,8 @@ namespace { getOverridableAccessibility(dc), /*IsStatic*/decl->isClassProperty(), /*IsLet*/false, /*IsCaptureList*/false, Impl.importSourceLoc(decl->getLocation()), - name, type, dc); - result->setInterfaceType(dc->mapTypeOutOfContext(type)); + name, dc->mapTypeIntoContext(type), dc); + result->setInterfaceType(type); // Turn this into a computed property. // FIXME: Fake locations for '{' and '}'? @@ -4930,6 +4929,7 @@ SwiftDeclConverter::importSwiftNewtype(const clang::TypedefNameDecl *decl, auto storedUnderlyingType = Impl.importType( decl->getUnderlyingType(), ImportTypeKind::Value, isInSystemModule(dc), decl->getUnderlyingType()->isBlockPointerType(), OTK_None); + if (auto objTy = storedUnderlyingType->getAnyOptionalObjectType()) storedUnderlyingType = objTy; @@ -5288,16 +5288,30 @@ Decl *SwiftDeclConverter::importGlobalAsMethod( auto &C = Impl.SwiftContext; SmallVector bodyParams; - // There is an inout 'self' when we have an instance method of a - // value-semantic type whose 'self' parameter is a - // pointer-to-non-const. + // There is an inout 'self' when the parameter is a pointer to a non-const + // instance of the type we're importing onto. Importing this as a method means + // that the method should be treated as mutating in this situation. bool selfIsInOut = false; if (selfIdx && !dc->getDeclaredTypeOfContext()->hasReferenceSemantics()) { auto selfParam = decl->getParamDecl(*selfIdx); auto selfParamTy = selfParam->getType(); if ((selfParamTy->isPointerType() || selfParamTy->isReferenceType()) && - !selfParamTy->getPointeeType().isConstQualified()) + !selfParamTy->getPointeeType().isConstQualified()) { selfIsInOut = true; + + // If there's a swift_newtype, check the levels of indirection: self is + // only inout if this is a pointer to the typedef type (which itself is a + // pointer). + if (auto nominalTypeDecl = + dc->getAsNominalTypeOrNominalTypeExtensionContext()) { + if (auto clangDCTy = dyn_cast_or_null( + nominalTypeDecl->getClangDecl())) + if (auto newtypeAttr = getSwiftNewtypeAttr(clangDCTy, getVersion())) + if (clangDCTy->getUnderlyingType().getCanonicalType() != + selfParamTy->getPointeeType().getCanonicalType()) + selfIsInOut = false; + } + } } bodyParams.push_back(ParameterList::createWithoutLoc(ParamDecl::createSelf( @@ -5474,7 +5488,8 @@ SwiftDeclConverter::getImplicitProperty(ImportedName importedName, auto property = Impl.createDeclWithClangNode( getter, Accessibility::Public, /*IsStatic*/isStatic, /*isLet*/false, - /*IsCaptureList*/false, SourceLoc(), propertyName, swiftPropertyType, dc); + /*IsCaptureList*/false, SourceLoc(), propertyName, + dc->mapTypeIntoContext(swiftPropertyType), dc); property->setInterfaceType(swiftPropertyType); // Note that we've formed this property. @@ -7001,6 +7016,41 @@ void ClangImporter::Implementation::importAttributes( PlatformAgnostic, /*Implicit=*/false); MappedDecl->getAttrs().add(AvAttr); + + // For enum cases introduced in the 2017 SDKs, add + // @_downgrade_exhaustivity_check in Swift 3. + if (C.LangOpts.isSwiftVersion3() && isa(MappedDecl)) { + bool downgradeExhaustivity = false; + switch (*platformK) { + case PlatformKind::OSX: + case PlatformKind::OSXApplicationExtension: + downgradeExhaustivity = (introduced.getMajor() == 10 && + introduced.getMinor() && + *introduced.getMinor() == 13); + break; + + case PlatformKind::iOS: + case PlatformKind::iOSApplicationExtension: + case PlatformKind::tvOS: + case PlatformKind::tvOSApplicationExtension: + downgradeExhaustivity = (introduced.getMajor() == 11); + break; + + case PlatformKind::watchOS: + case PlatformKind::watchOSApplicationExtension: + downgradeExhaustivity = (introduced.getMajor() == 4); + break; + + case PlatformKind::none: + break; + } + + if (downgradeExhaustivity) { + auto attr = + new (C) DowngradeExhaustivityCheckAttr(/*isImplicit=*/true); + MappedDecl->getAttrs().add(attr); + } + } } } @@ -7692,11 +7742,11 @@ ClangImporter::Implementation::createConstant(Identifier name, DeclContext *dc, var = createDeclWithClangNode(ClangN, Accessibility::Public, /*IsStatic*/isStatic, /*IsLet*/false, /*IsCaptureList*/false, SourceLoc(), - name, type, dc); + name, dc->mapTypeIntoContext(type), dc); } else { var = new (SwiftContext) VarDecl(/*IsStatic*/isStatic, /*IsLet*/false, /*IsCaptureList*/false, - SourceLoc(), name, type, dc); + SourceLoc(), name, dc->mapTypeIntoContext(type), dc); } var->setInterfaceType(type); @@ -7857,8 +7907,9 @@ ClangImporter::Implementation::loadAllMembers(Decl *D, uint64_t extra) { for (auto entry : table->lookupGlobalsAsMembers(effectiveClangContext)) { auto decl = entry.get(); - // Only continue members in the same submodule as this extension. - if (decl->getImportedOwningModule() != submodule) continue; + // Only include members in the same submodule as this extension. + if (getClangSubmoduleForDecl(decl) != submodule) + continue; forEachDistinctName(decl, [&](ImportedName newName, ImportNameVersion nameVersion) { @@ -7870,8 +7921,18 @@ ClangImporter::Implementation::loadAllMembers(Decl *D, uint64_t extra) { // Then try to import the decl under the specified name. auto *member = importDecl(decl, nameVersion); - if (!member || member->getDeclContext() != ext) - return; + if (!member) return; + + // Find the member that will land in an extension context. + while (!isa(member->getDeclContext())) { + auto nominal = dyn_cast(member->getDeclContext()); + if (!nominal) return; + + member = nominal; + if (member->hasClangNode()) return; + } + + if (member->getDeclContext() != ext) return; ext->addMember(member); for (auto alternate : getAlternateDecls(member)) { diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 0888fe1ad60..fae245eae36 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -564,7 +564,6 @@ namespace { // Pull the corresponding generic type parameter from the imported class. const auto *typeParamContext = objcTypeParamDecl->getDeclContext(); GenericSignature *genericSig = nullptr; - GenericEnvironment *genericEnv = nullptr; if (auto *category = dyn_cast(typeParamContext)) { auto ext = cast_or_null( @@ -572,7 +571,6 @@ namespace { if (!ext) return ImportResult(); genericSig = ext->getGenericSignature(); - genericEnv = ext->getGenericEnvironment(); } else if (auto *interface = dyn_cast(typeParamContext)) { auto cls = castIgnoringCompatibilityAlias( @@ -580,7 +578,6 @@ namespace { if (!cls) return ImportResult(); genericSig = cls->getGenericSignature(); - genericEnv = cls->getGenericEnvironment(); } unsigned index = objcTypeParamDecl->getIndex(); // Pull the generic param decl out of the imported class. @@ -592,8 +589,8 @@ namespace { if (index > genericSig->getGenericParams().size()) { return ImportResult(); } - auto *paramDecl = genericSig->getGenericParams()[index]; - return ImportResult(genericEnv->mapTypeIntoContext(paramDecl), + + return ImportResult(genericSig->getGenericParams()[index], ImportHint::ObjCPointer); } @@ -986,13 +983,12 @@ namespace { return Type(); // The first type argument for Dictionary or Set needs - // to be Hashable. Everything that inherits NSObject has a - // -hash code in ObjC, but if something isn't NSObject, fall back + // to be Hashable. If something isn't Hashable, fall back // to AnyHashable as a key type. if (unboundDecl == Impl.SwiftContext.getDictionaryDecl() || unboundDecl == Impl.SwiftContext.getSetDecl()) { auto &keyType = importedTypeArgs[0]; - if (!Impl.matchesNSObjectBound(keyType)) { + if (!Impl.matchesHashableBound(keyType)) { if (auto anyHashable = Impl.SwiftContext.getAnyHashableDecl()) keyType = anyHashable->getDeclaredType(); else @@ -1584,15 +1580,11 @@ Type ClangImporter::Implementation::importFunctionReturnType( } // Import the result type. - auto type = importType(clangDecl->getReturnType(), - (isAuditedResult ? ImportTypeKind::AuditedResult - : ImportTypeKind::Result), - allowNSUIntegerAsInt, - /*isFullyBridgeable*/ true, OptionalityOfReturn); - if (!type) - return type; - - return dc->mapTypeOutOfContext(type); + return importType(clangDecl->getReturnType(), + (isAuditedResult ? ImportTypeKind::AuditedResult + : ImportTypeKind::Result), + allowNSUIntegerAsInt, + /*isFullyBridgeable*/ true, OptionalityOfReturn); } Type ClangImporter::Implementation:: @@ -1683,10 +1675,11 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList( auto paramInfo = createDeclWithClangNode( param, Accessibility::Private, /*IsLet*/ true, SourceLoc(), SourceLoc(), name, - importSourceLoc(param->getLocation()), bodyName, swiftParamTy, + importSourceLoc(param->getLocation()), bodyName, + dc->mapTypeIntoContext(swiftParamTy), ImportedHeaderUnit); - paramInfo->setInterfaceType( - dc->mapTypeOutOfContext(swiftParamTy)); + + paramInfo->setInterfaceType(swiftParamTy); if (addNoEscapeAttr) paramInfo->getAttrs().add(new (SwiftContext) @@ -1875,6 +1868,21 @@ getForeignErrorInfo(ForeignErrorConvention::Info errorInfo, llvm_unreachable("bad error convention"); } +// Sometimes re-mapping type from one context to another is required, +// because the other context might have some of the generic parameters +// bound to concerete types, which means that we might loose generic +// signature when converting from class method to constructor and that +// is going to result in incorrect type interpretation of the method. +static Type mapTypeIntoContext(const DeclContext *fromDC, + const DeclContext *toDC, Type type) { + if (fromDC == toDC) + return toDC->mapTypeIntoContext(type); + + auto subs = toDC->getDeclaredTypeInContext()->getContextSubstitutionMap( + toDC->getParentModule(), fromDC); + return type.subst(subs); +} + Type ClangImporter::Implementation::importMethodType( const DeclContext *dc, const clang::ObjCMethodDecl *clangDecl, @@ -1909,22 +1917,6 @@ Type ClangImporter::Implementation::importMethodType( DeclContext *origDC = importDeclContextOf(clangDecl, clangDecl->getDeclContext()); assert(origDC); - auto mapTypeIntoContext = [&](Type type) -> Type { - if (dc != origDC) { - // Replace origDC's archetypes with interface types. - type = origDC->mapTypeOutOfContext(type); - - // Get the substitutions that we need to access a member of - // 'origDC' on 'dc'. - auto subs = dc->getDeclaredTypeInContext() - ->getContextSubstitutionMap(dc->getParentModule(), origDC); - - // Apply them to the interface type to produce the final - // substituted type. - type = type.subst(subs); - } - return type; - }; // Import the result type. CanType origSwiftResultTy; @@ -1985,9 +1977,11 @@ Type ClangImporter::Implementation::importMethodType( swiftResultTy = OptionalType::get(OptionalityOfReturn, swiftResultTy); } } + if (!swiftResultTy) return Type(); - swiftResultTy = mapTypeIntoContext(swiftResultTy); + + swiftResultTy = mapTypeIntoContext(origDC, dc, swiftResultTy); CanType errorParamType; @@ -2078,6 +2072,8 @@ Type ClangImporter::Implementation::importMethodType( if (!swiftParamTy) return Type(); + swiftParamTy = mapTypeIntoContext(origDC, dc, swiftParamTy); + // If this is the error parameter, remember it, but don't build it // into the parameter type. if (paramIsError) { @@ -2113,20 +2109,16 @@ Type ClangImporter::Implementation::importMethodType( } ++nameIndex; - // It doesn't actually matter which DeclContext we use, so just use the - // imported header unit. - swiftParamTy = mapTypeIntoContext(swiftParamTy); - // Set up the parameter info. auto paramInfo = createDeclWithClangNode(param, Accessibility::Private, /*IsLet*/ true, SourceLoc(), SourceLoc(), name, importSourceLoc(param->getLocation()), - bodyName, swiftParamTy, + bodyName, + swiftParamTy, ImportedHeaderUnit); - paramInfo->setInterfaceType( - dc->mapTypeOutOfContext(swiftParamTy)); + paramInfo->setInterfaceType(dc->mapTypeOutOfContext(swiftParamTy)); if (addNoEscapeAttr) { paramInfo->getAttrs().add( @@ -2192,13 +2184,10 @@ Type ClangImporter::Implementation::importMethodType( // Mark that the function type throws. extInfo = extInfo.withThrows(true); } - - swiftResultTy = dc->mapTypeOutOfContext(swiftResultTy); // Form the function type. - return FunctionType::get( - (*bodyParams)->getInterfaceType(SwiftContext), - swiftResultTy, extInfo); + return FunctionType::get((*bodyParams)->getInterfaceType(SwiftContext), + dc->mapTypeOutOfContext(swiftResultTy), extInfo); } Type ClangImporter::Implementation::importAccessorMethodType( @@ -2227,36 +2216,18 @@ Type ClangImporter::Implementation::importAccessorMethodType( DeclContext *origDC = importDeclContextOf(property, property->getDeclContext()); assert(origDC); - auto mapTypeIntoContext = [&](Type type) -> Type { - if (dc != origDC) { - // Replace origDC's archetypes with interface types. - type = origDC->mapTypeOutOfContext(type); - - // Get the substitutions that we need to access a member of - // 'origDC' on 'dc'. - auto subs = dc->getDeclaredTypeInContext() - ->getContextSubstitutionMap(dc->getParentModule(), origDC); - - // Apply them to the interface type to produce the final - // substituted type. - type = type.subst(subs); - } - return type; - }; // Import the property type, independent of what kind of accessor this is. Type propertyTy = importPropertyType(property, isFromSystemModule); if (!propertyTy) return Type(); - propertyTy = mapTypeIntoContext(propertyTy); - Type propertyInterfaceTy = dc->mapTypeOutOfContext(propertyTy); + propertyTy = mapTypeIntoContext(origDC, dc, propertyTy); // Now build up the resulting FunctionType and parameters. Type resultTy; if (isGetter) { *params = ParameterList::createEmpty(SwiftContext); - resultTy = propertyInterfaceTy; - + resultTy = dc->mapTypeOutOfContext(propertyTy); } else { const clang::ParmVarDecl *param = clangDecl->parameters().front(); ImportedName fullBodyName = importFullName(param, CurrentVersion); @@ -2271,7 +2242,7 @@ Type ClangImporter::Implementation::importAccessorMethodType( argLabel, nameLoc, bodyName, propertyTy, /*dummy DC*/ImportedHeaderUnit); - paramInfo->setInterfaceType(propertyInterfaceTy); + paramInfo->setInterfaceType(dc->mapTypeOutOfContext(propertyTy)); *params = ParameterList::create(SwiftContext, paramInfo); resultTy = SwiftContext.getVoidDecl()->getDeclaredInterfaceType(); @@ -2440,7 +2411,7 @@ Type ClangImporter::Implementation::getNSObjectType() { return Type(); } -bool ClangImporter::Implementation::matchesNSObjectBound(Type type) { +bool ClangImporter::Implementation::matchesHashableBound(Type type) { Type NSObjectType = getNSObjectType(); if (!NSObjectType) return false; @@ -2452,8 +2423,14 @@ bool ClangImporter::Implementation::matchesNSObjectBound(Type type) { // Struct or enum type must have been bridged. // TODO: Check that the bridged type is Hashable? if (type->getStructOrBoundGenericStruct() || - type->getEnumOrBoundGenericEnum()) - return true; + type->getEnumOrBoundGenericEnum()) { + auto nominal = type->getAnyNominal(); + auto hashable = SwiftContext.getProtocol(KnownProtocolKind::Hashable); + SmallVector conformances; + return hashable && + nominal->lookupConformance(nominal->getParentModule(), hashable, + conformances); + } return false; } diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index d1462a939c9..25c964d5621 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -886,7 +886,7 @@ public: /// \brief Determines whether the given type matches an implicit type /// bound of "Hashable", which is used to validate NSDictionary/NSSet. - bool matchesNSObjectBound(Type type); + bool matchesHashableBound(Type type); /// \brief Look up and attempt to import a Clang declaration with /// the given name. diff --git a/lib/Demangling/Context.cpp b/lib/Demangling/Context.cpp index 6d413a583e8..c11245da157 100644 --- a/lib/Demangling/Context.cpp +++ b/lib/Demangling/Context.cpp @@ -36,14 +36,9 @@ void Context::clear() { } NodePointer Context::demangleSymbolAsNode(llvm::StringRef MangledName) { -#ifndef NO_NEW_DEMANGLING - if (MangledName.startswith(MANGLING_PREFIX_STR) - // Also accept the future mangling prefix. - // TODO: remove this line as soon as MANGLING_PREFIX_STR gets "_S". - || MangledName.startswith("_S")) { + if (isMangledName(MangledName.data())) { return D->demangleSymbol(MangledName); } -#endif return demangleOldSymbolAsNode(MangledName, *D); } @@ -74,10 +69,7 @@ std::string Context::demangleTypeAsString(llvm::StringRef MangledName, } bool Context::isThunkSymbol(llvm::StringRef MangledName) { - if (MangledName.startswith(MANGLING_PREFIX_STR) - // Also accept the future mangling prefix. - // TODO: remove this line as soon as MANGLING_PREFIX_STR gets "_S". - || MangledName.startswith("_S")) { + if (isMangledName(MangledName)) { // First do a quick check if (MangledName.endswith("TA") || // partial application forwarder MangledName.endswith("Ta") || // ObjC partial application forwarder @@ -126,11 +118,7 @@ std::string Context::getThunkTarget(llvm::StringRef MangledName) { if (!isThunkSymbol(MangledName)) return std::string(); - if (MangledName.startswith(MANGLING_PREFIX_STR) - // Also accept the future mangling prefix. - // TODO: remove this line as soon as MANGLING_PREFIX_STR gets "_S". - || MangledName.startswith("_S")) { - + if (isMangledName(MangledName)) { // The targets of those thunks not derivable from the mangling. if (MangledName.endswith("TR") || MangledName.endswith("Tr") || diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index 777d6d6603e..e3b8b48c175 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -109,6 +109,31 @@ static bool isFunctionAttr(Node::Kind kind) { } // anonymous namespace +////////////////////////////////// +// Public utility functions // +////////////////////////////////// + +int swift::Demangle::getManglingPrefixLength(const char *mangledName) { + // Check for the swift-4 prefix + if (mangledName[0] == '_' && mangledName[1] == 'T' && mangledName[2] == '0') + return 3; + + // Check for the swift > 4 prefix + unsigned Offset = (mangledName[0] == '_' ? 1 : 0); + if (mangledName[Offset] == '$' && mangledName[Offset + 1] == 'S') + return Offset + 2; + + return 0; +} + +bool swift::Demangle::isSwiftSymbol(const char *mangledName) { + // The old mangling. + if (mangledName[0] == '_' && mangledName[1] == 'T') + return true; + + return getManglingPrefixLength(mangledName) != 0; +} + namespace swift { namespace Demangle { @@ -226,12 +251,12 @@ NodePointer Demangler::demangleSymbol(StringRef MangledName) { if (nextIf("_Tt")) return demangleObjCTypeName(); - if (!nextIf(MANGLING_PREFIX_STR) - // Also accept the future mangling prefix. - // TODO: remove this line as soon as MANGLING_PREFIX_STR gets "_S". - && !nextIf("_S")) + unsigned PrefixLength = getManglingPrefixLength(MangledName.data()); + if (PrefixLength == 0) return nullptr; + Pos += PrefixLength; + // If any other prefixes are accepted, please update Mangler::verify. if (!parseAndPushNodes()) @@ -393,6 +418,11 @@ NodePointer Demangler::demangleOperator() { case 'z': return createType(createWithChild(Node::Kind::InOut, popTypeAndGetChild())); case '_': return createNode(Node::Kind::FirstElementMarker); + case '.': + // IRGen still uses '.' to disambiguate partial apply thunks and + // outlined copy functions. We treat such a suffix as "unmangled suffix". + pushBack(); + return createNode(Node::Kind::Suffix, consumeAll()); default: pushBack(); return demangleIdentifier(); diff --git a/lib/Demangling/OldDemangler.cpp b/lib/Demangling/OldDemangler.cpp index b558192d93f..9f92584a253 100644 --- a/lib/Demangling/OldDemangler.cpp +++ b/lib/Demangling/OldDemangler.cpp @@ -2199,23 +2199,6 @@ private: }; } // end anonymous namespace - -bool -swift::Demangle::isSwiftSymbol(const char *mangledName) { - // The old mangling. - if (mangledName[0] == '_' - // Also accept the future mangling prefix. - && (mangledName[1] == 'T' || mangledName[1] == 'S')) - return true; - - // The new mangling. - for (unsigned i = 0; i < sizeof(MANGLING_PREFIX_STR) - 1; i++) { - if (mangledName[i] != MANGLING_PREFIX_STR[i]) - return false; - } - return true; -} - NodePointer swift::Demangle::demangleOldSymbolAsNode(StringRef MangledName, NodeFactory &Factory) { diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 4c4672e95b2..a5323a9a8e2 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -1315,7 +1315,11 @@ void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args, OI.SelectedSanitizer = SanitizerKind::None; if (const Arg *A = Args.getLastArg(options::OPT_sanitize_EQ)) - OI.SelectedSanitizer = parseSanitizerArgValues(A, TC.getTriple(), Diags); + OI.SelectedSanitizer = parseSanitizerArgValues( + A, TC.getTriple(), Diags, + [&](StringRef sanitizerName) { + return TC.sanitizerRuntimeLibExists(Args, sanitizerName); + }); // Check that the sanitizer coverage flags are supported if supplied. if (const Arg *A = Args.getLastArg(options::OPT_sanitize_coverage_EQ)) diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index 2e1a004e4b9..7edf218eb37 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -149,3 +149,11 @@ ToolChain::findProgramRelativeToSwiftImpl(StringRef executableName) const { types::ID ToolChain::lookupTypeForExtension(StringRef Ext) const { return types::lookupTypeForExtension(Ext); } + +bool +ToolChain::sanitizerRuntimeLibExists(const ArgList &args, + StringRef sanitizerName) const { + // Assume no sanitizers are supported by default. + // This method should be overriden by a platform-specific subclass. + return false; +} diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index eafeb2084d7..d54e990b522 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -965,6 +965,15 @@ static void getRuntimeLibraryPath(SmallVectorImpl &runtimeLibPath, getPlatformNameForTriple(TC.getTriple())); } +static void getClangLibraryPathOnDarwin(SmallVectorImpl &libPath, + const ArgList &args, + const ToolChain &TC) { + getRuntimeLibraryPath(libPath, args, TC); + // Remove platform name. + llvm::sys::path::remove_filename(libPath); + llvm::sys::path::append(libPath, "clang", "lib", "darwin"); +} + /// Get the runtime library link path for static linking, /// which is platform-specific and found relative to the compiler. static void getRuntimeStaticLibraryPath(SmallVectorImpl &runtimeLibPath, @@ -1025,16 +1034,31 @@ getDarwinLibraryNameSuffixForTriple(const llvm::Triple &triple) { llvm_unreachable("Unsupported Darwin platform"); } +static std::string +getSanitizerRuntimeLibNameForDarwin(StringRef Sanitizer, const llvm::Triple &Triple) { + return (Twine("libclang_rt.") + + Sanitizer + "_" + + getDarwinLibraryNameSuffixForTriple(Triple) + "_dynamic.dylib").str(); +} + +bool toolchains::Darwin::sanitizerRuntimeLibExists( + const ArgList &args, StringRef sanitizer) const { + SmallString<128> sanitizerLibPath; + getClangLibraryPathOnDarwin(sanitizerLibPath, args, *this); + llvm::sys::path::append(sanitizerLibPath, + getSanitizerRuntimeLibNameForDarwin(sanitizer, this->getTriple())); + return llvm::sys::fs::exists(sanitizerLibPath.str()); +} + + static void addLinkRuntimeLibForDarwin(const ArgList &Args, ArgStringList &Arguments, StringRef DarwinLibName, bool AddRPath, const ToolChain &TC) { - SmallString<128> Dir; - getRuntimeLibraryPath(Dir, Args, TC); - // Remove platform name. - llvm::sys::path::remove_filename(Dir); - llvm::sys::path::append(Dir, "clang", "lib", "darwin"); - SmallString<128> P(Dir); + SmallString<128> ClangLibraryPath; + getClangLibraryPathOnDarwin(ClangLibraryPath, Args, TC); + + SmallString<128> P(ClangLibraryPath); llvm::sys::path::append(P, DarwinLibName); Arguments.push_back(Args.MakeArgString(P)); @@ -1053,7 +1077,7 @@ addLinkRuntimeLibForDarwin(const ArgList &Args, ArgStringList &Arguments, // Add the path to the resource dir to rpath to support using the dylib // from the default location without copying. Arguments.push_back("-rpath"); - Arguments.push_back(Args.MakeArgString(Dir)); + Arguments.push_back(Args.MakeArgString(ClangLibraryPath)); } } @@ -1068,10 +1092,8 @@ addLinkSanitizerLibArgsForDarwin(const ArgList &Args, Arguments.push_back("-lc++abi"); addLinkRuntimeLibForDarwin(Args, Arguments, - (Twine("libclang_rt.") + Sanitizer + "_" + - getDarwinLibraryNameSuffixForTriple(TC.getTriple()) + - "_dynamic.dylib").str(), - /*AddRPath*/ true, TC); + getSanitizerRuntimeLibNameForDarwin(Sanitizer, TC.getTriple()), + /*AddRPath=*/ true, TC); } ToolChain::InvocationInfo @@ -1245,6 +1267,10 @@ toolchains::Darwin::constructInvocation(const LinkJobAction &job, Arguments.push_back("-force_load_swift_libs"); } else { Arguments.push_back(context.Args.MakeArgString(RuntimeLibPath)); + // FIXME: We probably shouldn't be adding an rpath here unless we know ahead + // of time the standard library won't be copied. SR-1967 + Arguments.push_back("-rpath"); + Arguments.push_back(context.Args.MakeArgString(RuntimeLibPath)); } if (context.Args.hasArg(options::OPT_profile_generate)) { @@ -1283,11 +1309,6 @@ toolchains::Darwin::constructInvocation(const LinkJobAction &job, Arguments.push_back(context.Args.MakeArgString(LibProfile)); } - // FIXME: We probably shouldn't be adding an rpath here unless we know ahead - // of time the standard library won't be copied. - Arguments.push_back("-rpath"); - Arguments.push_back(context.Args.MakeArgString(RuntimeLibPath)); - // FIXME: Properly handle deployment targets. assert(Triple.isiOS() || Triple.isWatchOS() || Triple.isMacOSX()); if (Triple.isiOS()) { diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index eb0c2e3f9c5..6d980ccd59d 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -33,7 +33,9 @@ protected: public: Darwin(const Driver &D, const llvm::Triple &Triple) : ToolChain(D, Triple) {} ~Darwin() = default; - + bool sanitizerRuntimeLibExists(const llvm::opt::ArgList &args, + StringRef sanitizerLibName) + const override; }; class LLVM_LIBRARY_VISIBILITY GenericUnix : public ToolChain { diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index f086f0c3f04..76a93c5bc89 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -226,6 +226,16 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, } } + if (const Arg *A = Args.getLastArg(OPT_solver_expression_time_threshold_EQ)) { + unsigned attempt; + if (StringRef(A->getValue()).getAsInteger(10, attempt)) { + Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value, + A->getAsString(Args), A->getValue()); + } else { + Opts.SolverExpressionTimeThreshold = attempt; + } + } + Opts.PlaygroundTransform |= Args.hasArg(OPT_playground); if (Args.hasArg(OPT_disable_playground_transform)) Opts.PlaygroundTransform = false; @@ -857,7 +867,6 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Args.hasArg(OPT_serialize_debugging_options); Opts.EnableSourceImport |= Args.hasArg(OPT_enable_source_import); Opts.ImportUnderlyingModule |= Args.hasArg(OPT_import_underlying_module); - Opts.SILSerializeAll |= Args.hasArg(OPT_sil_serialize_all); Opts.EnableSerializationNestedTypeLookupTable &= !Args.hasArg(OPT_disable_serialization_nested_type_lookup_table); @@ -1320,6 +1329,10 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args, if (Args.hasArg(OPT_sil_merge_partial_modules)) Opts.MergePartialModules = true; + Opts.SILSerializeAll |= Args.hasArg(OPT_sil_serialize_all); + Opts.SILSerializeWitnessTables |= + Args.hasArg(OPT_sil_serialize_witness_tables); + // Parse the optimization level. if (const Arg *A = Args.getLastArg(OPT_O_Group)) { if (A->getOption().matches(OPT_Onone)) { @@ -1411,7 +1424,14 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args, } if (const Arg *A = Args.getLastArg(options::OPT_sanitize_EQ)) { - Opts.Sanitize = parseSanitizerArgValues(A, Triple, Diags); + Opts.Sanitize = parseSanitizerArgValues( + A, Triple, Diags, + /* sanitizerRuntimeLibExists= */[](StringRef libName) { + + // The driver has checked the existence of the library + // already. + return true; + }); IRGenOpts.Sanitize = Opts.Sanitize; } diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index dbae78950db..07041894bef 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -55,8 +55,7 @@ std::string CompilerInvocation::getPCHHash() const { void CompilerInstance::createSILModule(bool WholeModule) { assert(MainModule && "main module not created yet"); TheSILModule = SILModule::createEmptyModule( - getMainModule(), Invocation.getSILOptions(), WholeModule, - Invocation.getFrontendOptions().SILSerializeAll); + getMainModule(), Invocation.getSILOptions(), WholeModule); } void CompilerInstance::setPrimarySourceFile(SourceFile *SF) { @@ -250,7 +249,7 @@ ModuleDecl *CompilerInstance::getMainModule() { if (Invocation.getFrontendOptions().EnableResilience) MainModule->setResilienceStrategy(ResilienceStrategy::Resilient); - else if (Invocation.getFrontendOptions().SILSerializeAll) + else if (Invocation.getSILOptions().SILSerializeAll) MainModule->setResilienceStrategy(ResilienceStrategy::Fragile); } return MainModule; @@ -520,7 +519,8 @@ void CompilerInstance::performSema() { performTypeChecking(MainFile, PersistentState.getTopLevelContext(), TypeCheckOptions, CurTUElem, options.WarnLongFunctionBodies, - options.WarnLongExpressionTypeChecking); + options.WarnLongExpressionTypeChecking, + options.SolverExpressionTimeThreshold); } CurTUElem = MainFile.Decls.size(); } while (!Done); @@ -549,7 +549,8 @@ void CompilerInstance::performSema() { performTypeChecking(*SF, PersistentState.getTopLevelContext(), TypeCheckOptions, /*curElem*/ 0, options.WarnLongFunctionBodies, - options.WarnLongExpressionTypeChecking); + options.WarnLongExpressionTypeChecking, + options.SolverExpressionTimeThreshold); // Even if there were no source files, we should still record known // protocols. diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 561eda3ea28..45a561494c2 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -665,8 +665,10 @@ static bool performCompile(CompilerInstance &Instance, } if (Action == FrontendOptions::EmitTBD) { - auto hasMultipleIRGenThreads = Invocation.getSILOptions().NumThreads > 1; + const auto &silOpts = Invocation.getSILOptions(); + auto hasMultipleIRGenThreads = silOpts.NumThreads > 1; return writeTBD(Instance.getMainModule(), hasMultipleIRGenThreads, + silOpts.SILSerializeWitnessTables, opts.getSingleOutputFilename()); } @@ -691,13 +693,13 @@ static bool performCompile(CompilerInstance &Instance, } astGuaranteedToCorrespondToSIL = !fileIsSIB(PrimaryFile); SM = performSILGeneration(*PrimaryFile, Invocation.getSILOptions(), - None, opts.SILSerializeAll); + None); } else { auto mod = Instance.getMainModule(); astGuaranteedToCorrespondToSIL = llvm::none_of(mod->getFiles(), fileIsSIB); SM = performSILGeneration(mod, Invocation.getSILOptions(), - opts.SILSerializeAll, true); + true); } } @@ -835,7 +837,8 @@ static bool performCompile(CompilerInstance &Instance, serializationOpts.OutputPath = opts.ModuleOutputPath.c_str(); serializationOpts.DocOutputPath = opts.ModuleDocOutputPath.c_str(); serializationOpts.GroupInfoPath = opts.GroupInfoPath.c_str(); - serializationOpts.SerializeAllSIL = opts.SILSerializeAll; + serializationOpts.SerializeAllSIL = + Invocation.getSILOptions().SILSerializeAll; if (opts.SerializeBridgingHeader) serializationOpts.ImportedHeader = opts.ImplicitObjCHeaderPath; serializationOpts.ModuleLinkName = opts.ModuleLinkName; @@ -941,14 +944,16 @@ static bool performCompile(CompilerInstance &Instance, !astGuaranteedToCorrespondToSIL) break; - auto hasMultipleIRGenThreads = Invocation.getSILOptions().NumThreads > 1; + const auto &silOpts = Invocation.getSILOptions(); + auto hasMultipleIRGenThreads = silOpts.NumThreads > 1; bool error; if (PrimarySourceFile) error = validateTBD(PrimarySourceFile, *IRModule, hasMultipleIRGenThreads, - allSymbols); + silOpts.SILSerializeWitnessTables, allSymbols); else error = validateTBD(Instance.getMainModule(), *IRModule, - hasMultipleIRGenThreads, allSymbols); + hasMultipleIRGenThreads, + silOpts.SILSerializeWitnessTables, allSymbols); if (error) return true; diff --git a/lib/FrontendTool/ReferenceDependencies.cpp b/lib/FrontendTool/ReferenceDependencies.cpp index b3c8fce281f..f1b34579fb2 100644 --- a/lib/FrontendTool/ReferenceDependencies.cpp +++ b/lib/FrontendTool/ReferenceDependencies.cpp @@ -150,8 +150,7 @@ bool swift::emitReferenceDependencies(DiagnosticEngine &diags, } auto escape = [](DeclBaseName name) -> std::string { - // TODO: Handle special names - return llvm::yaml::escape(name.getIdentifier().str()); + return llvm::yaml::escape(name.userFacingName()); }; out << "### Swift dependencies file v0 ###\n"; diff --git a/lib/FrontendTool/TBD.cpp b/lib/FrontendTool/TBD.cpp index 9c682190691..1b841d7201c 100644 --- a/lib/FrontendTool/TBD.cpp +++ b/lib/FrontendTool/TBD.cpp @@ -39,7 +39,7 @@ static std::vector sortSymbols(llvm::StringSet<> &symbols) { } bool swift::writeTBD(ModuleDecl *M, bool hasMultipleIRGenThreads, - StringRef OutputFilename) { + bool silSerializeWitnessTables, StringRef OutputFilename) { std::error_code EC; llvm::raw_fd_ostream OS(OutputFilename, EC, llvm::sys::fs::F_None); if (EC) { @@ -50,7 +50,7 @@ bool swift::writeTBD(ModuleDecl *M, bool hasMultipleIRGenThreads, llvm::StringSet<> symbols; for (auto file : M->getFiles()) enumeratePublicSymbols(file, symbols, hasMultipleIRGenThreads, - /*isWholeModule=*/true); + /*isWholeModule=*/true, silSerializeWitnessTables); // Ensure the order is stable. for (auto &symbol : sortSymbols(symbols)) { @@ -125,11 +125,12 @@ static bool validateSymbolSet(DiagnosticEngine &diags, bool swift::validateTBD(ModuleDecl *M, llvm::Module &IRModule, bool hasMultipleIRGenThreads, + bool silSerializeWitnessTables, bool diagnoseExtraSymbolsInTBD) { llvm::StringSet<> symbols; for (auto file : M->getFiles()) enumeratePublicSymbols(file, symbols, hasMultipleIRGenThreads, - /*isWholeModule=*/true); + /*isWholeModule=*/true, silSerializeWitnessTables); return validateSymbolSet(M->getASTContext().Diags, symbols, IRModule, diagnoseExtraSymbolsInTBD); @@ -137,10 +138,11 @@ bool swift::validateTBD(ModuleDecl *M, llvm::Module &IRModule, bool swift::validateTBD(FileUnit *file, llvm::Module &IRModule, bool hasMultipleIRGenThreads, + bool silSerializeWitnessTables, bool diagnoseExtraSymbolsInTBD) { llvm::StringSet<> symbols; enumeratePublicSymbols(file, symbols, hasMultipleIRGenThreads, - /*isWholeModule=*/false); + /*isWholeModule=*/false, silSerializeWitnessTables); return validateSymbolSet(file->getParentModule()->getASTContext().Diags, symbols, IRModule, diagnoseExtraSymbolsInTBD); diff --git a/lib/FrontendTool/TBD.h b/lib/FrontendTool/TBD.h index cff17201129..98b2c8b160c 100644 --- a/lib/FrontendTool/TBD.h +++ b/lib/FrontendTool/TBD.h @@ -25,12 +25,14 @@ class FileUnit; class FrontendOptions; bool writeTBD(ModuleDecl *M, bool hasMultipleIRGenThreads, - llvm::StringRef OutputFilename); + bool silSerializeWitnessTables, llvm::StringRef OutputFilename); bool inputFileKindCanHaveTBDValidated(InputFileKind kind); bool validateTBD(ModuleDecl *M, llvm::Module &IRModule, - bool hasMultipleIRGenThreads, bool diagnoseExtraSymbolsInTBD); + bool hasMultipleIRGenThreads, bool silSerializeWitnessTables, + bool diagnoseExtraSymbolsInTBD); bool validateTBD(FileUnit *M, llvm::Module &IRModule, - bool hasMultipleIRGenThreads, bool diagnoseExtraSymbolsInTBD); + bool hasMultipleIRGenThreads, bool silSerializeWitnessTables, + bool diagnoseExtraSymbolsInTBD); } #endif diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index 30b546e2785..8abcdec7d5a 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -1548,20 +1548,18 @@ protocolForLiteralKind(CodeCompletionLiteralKind kind) { /// that is of type () -> (). static bool hasTrivialTrailingClosure(const FuncDecl *FD, AnyFunctionType *funcType) { - unsigned level = FD->isInstanceMember() ? 1 : 0; - auto Args = decomposeParamType(funcType->getInput(), FD, level); - bool OneArg = Args.size() == 1; - if (Args.size() > 1) { - unsigned NonDefault = - std::count_if(Args.begin(), Args.end() - 1, [](const CallArgParam &P) { - return !P.HasDefaultArgument; - }); - - OneArg = NonDefault == 0; + SmallVector defaultMap; + computeDefaultMap(funcType->getInput(), FD, + /*level*/ FD->isInstanceMember() ? 1 : 0, defaultMap); + + bool OneArg = defaultMap.size() == 1; + if (defaultMap.size() > 1) { + auto NonDefault = std::count(defaultMap.begin(), defaultMap.end() - 1, false); + OneArg = (NonDefault == 0); } if (OneArg) - if (auto Fn = Args.back().Ty->getAs()) + if (auto Fn = funcType->getParams().back().getType()->getAs()) return Fn->getInput()->isVoid() && Fn->getResult()->isVoid(); return false; @@ -3729,7 +3727,8 @@ public: for (auto Ex : NTD->getExtensions()) { handleDeclRange(Ex->getMembers(), Reason); } - } else if (isNameHit(VD->getNameStr())) { + } else if (!VD->getBaseName().isSpecial() && + isNameHit(VD->getBaseName().getIdentifier().str())) { if (VD->hasInterfaceType()) unboxType(VD->getInterfaceType()); } diff --git a/lib/IDE/CommentConversion.cpp b/lib/IDE/CommentConversion.cpp index 0c8a16e43e3..cdbd8ecb1d2 100644 --- a/lib/IDE/CommentConversion.cpp +++ b/lib/IDE/CommentConversion.cpp @@ -245,6 +245,19 @@ struct CommentToXMLConverter { OS << ""; } + void printTagFields(ArrayRef Tags) { + OS << ""; + for (const auto Tag : Tags) { + if (Tag.empty()) { + continue; + } + OS << ""; + appendWithXMLEscaping(OS, Tag); + OS << ""; + } + OS << ""; + } + void visitDocComment(const DocComment *DC); void visitCommentParts(const swift::markup::CommentParts &Parts); }; @@ -271,6 +284,10 @@ void CommentToXMLConverter::visitCommentParts(const swift::markup::CommentParts if (Parts.ThrowsField.hasValue()) printThrowsDiscussion(Parts.ThrowsField.getValue()); + if (!Parts.Tags.empty()) { + printTagFields(Parts.Tags); + } + if (!Parts.BodyNodes.empty()) { OS << ""; for (const auto *N : Parts.BodyNodes) diff --git a/lib/IDE/Formatting.cpp b/lib/IDE/Formatting.cpp index 35499c1980d..2952cbcf881 100644 --- a/lib/IDE/Formatting.cpp +++ b/lib/IDE/Formatting.cpp @@ -652,7 +652,7 @@ class FormatWalker : public SourceEntityWalker { /// Sometimes, target is a part of "parent", for instance, "#else" is a part /// of an ifconfigstmt, so that ifconfigstmt is not really the parent of "#else". bool isTargetPartOf(swift::ASTWalker::ParentTy Parent) { - if (auto Conf = dyn_cast_or_null(Parent.getAsStmt())) { + if (auto Conf = dyn_cast_or_null(Parent.getAsDecl())) { for (auto Clause : Conf->getClauses()) { if (Clause.Loc == TargetLocation) return true; diff --git a/lib/IDE/ModuleInterfacePrinting.cpp b/lib/IDE/ModuleInterfacePrinting.cpp index 119c9d68a63..fd6935f22e0 100644 --- a/lib/IDE/ModuleInterfacePrinting.cpp +++ b/lib/IDE/ModuleInterfacePrinting.cpp @@ -220,28 +220,49 @@ swift::ide::collectModuleGroups(ModuleDecl *M, std::vector &Scratch) return llvm::makeArrayRef(Scratch); } -/// Determine whether the given extension has a Clang node that -/// created it (vs. being a Swift extension). -static bool extensionHasClangNode(ExtensionDecl *ext) { - // If it has a Clang node (directly), - if (ext->hasClangNode()) return true; +/// Retrieve the effective Clang node for the given declaration, which +/// copes with the odd case of imported Error enums. +static ClangNode getEffectiveClangNode(const Decl *decl) { + // Directly... + if (auto clangNode = decl->getClangNode()) + return clangNode; - // If it has a global imported as a member. - auto members = ext->getMembers(); - if (members.empty()) return false; - return members.front()->hasClangNode(); + // Or via the nested "Code" enum. + if (auto nominal = + const_cast(dyn_cast(decl))) { + auto &ctx = nominal->getASTContext(); + for (auto code : nominal->lookupDirect(ctx.Id_Code, + /*ignoreNewExtensions=*/true)) { + if (auto clangDecl = code->getClangDecl()) + return clangDecl; + } + } + + return ClangNode(); } /// Retrieve the Clang node for the given extension, if it has one. -/// created it (vs. being a Swift extension). static ClangNode extensionGetClangNode(ExtensionDecl *ext) { // If it has a Clang node (directly), if (ext->hasClangNode()) return ext->getClangNode(); - // If it has a global imported as a member. - auto members = ext->getMembers(); - if (members.empty()) return ClangNode(); - return members.front()->getClangNode(); + // Check whether it was syntheszed into a module-scope context. + if (!isa(ext->getModuleScopeContext())) + return ClangNode(); + + // It may have a global imported as a member. + for (auto member : ext->getMembers()) { + if (auto clangNode = getEffectiveClangNode(member)) + return clangNode; + } + + return ClangNode(); +} + +/// Determine whether the given extension has a Clang node that +/// created it (vs. being a Swift extension). +static bool extensionHasClangNode(ExtensionDecl *ext) { + return static_cast(extensionGetClangNode(ext)); } Optional @@ -393,8 +414,8 @@ void swift::ide::printSubmoduleInterface( } }; - if (D->hasClangNode()) { - addToClangDecls(D, D->getClangNode()); + if (auto clangNode = getEffectiveClangNode(D)) { + addToClangDecls(D, clangNode); continue; } @@ -739,8 +760,8 @@ void swift::ide::printHeaderInterface( std::sort(ClangDecls.begin(), ClangDecls.end(), [&](Decl *LHS, Decl *RHS) -> bool { return ClangSM.isBeforeInTranslationUnit( - LHS->getClangNode().getLocation(), - RHS->getClangNode().getLocation()); + getEffectiveClangNode(LHS).getLocation(), + getEffectiveClangNode(RHS).getLocation()); }); ASTPrinter *PrinterToUse = &Printer; @@ -789,7 +810,7 @@ void ClangCommentPrinter::printDeclPre(const Decl *D, // single line. // FIXME: we should fix that, since it also affects struct members, etc. if (!isa(D)) { - if (auto ClangN = D->getClangNode()) { + if (auto ClangN = getEffectiveClangNode(D)) { printCommentsUntil(ClangN); if (shouldPrintNewLineBefore(ClangN)) { *this << "\n"; @@ -813,7 +834,7 @@ void ClangCommentPrinter::printDeclPost(const Decl *D, *this << " " << ASTPrinter::sanitizeUtf8(CommentText); } PendingComments.clear(); - if (auto ClangN = D->getClangNode()) + if (auto ClangN = getEffectiveClangNode(D)) updateLastEntityLine(ClangN.getSourceRange().getEnd()); } diff --git a/lib/IDE/SwiftSourceDocInfo.cpp b/lib/IDE/SwiftSourceDocInfo.cpp index 400c3babc7f..5e6cfd04c14 100644 --- a/lib/IDE/SwiftSourceDocInfo.cpp +++ b/lib/IDE/SwiftSourceDocInfo.cpp @@ -108,6 +108,14 @@ bool SemaLocResolver::tryResolve(Stmt *St) { return false; } +bool SemaLocResolver::tryResolve(Expr *Exp) { + if (!Exp->isImplicit() && Exp->getStartLoc() == LocToResolve) { + SemaTok = { Exp }; + return true; + } + return false; +} + bool SemaLocResolver::visitSubscriptReference(ValueDecl *D, CharSourceRange Range, bool IsOpenBracket) { // We should treat both open and close brackets equally @@ -189,6 +197,12 @@ bool SemaLocResolver::walkToExprPre(Expr *E) { return true; } +bool SemaLocResolver::walkToExprPost(Expr *E) { + if (isDone()) + return false; + return !tryResolve(E); +} + bool SemaLocResolver::visitCallArgName(Identifier Name, CharSourceRange Range, ValueDecl *D) { if (isDone()) @@ -277,7 +291,7 @@ void ResolvedRangeInfo::print(llvm::raw_ostream &OS) { } for (auto &VD : DeclaredDecls) { - OS << "" << VD.VD->getNameStr() << ""; + OS << "" << VD.VD->getBaseName() << ""; OS << ""; if (VD.ReferredAfterRange) OS << "true"; @@ -286,7 +300,7 @@ void ResolvedRangeInfo::print(llvm::raw_ostream &OS) { OS << "\n"; } for (auto &RD : ReferencedDecls) { - OS << "" << RD.VD->getNameStr() << ""; + OS << "" << RD.VD->getBaseName() << ""; OS << ""; RD.Ty->print(OS); OS << "\n"; @@ -1009,8 +1023,7 @@ void swift::ide::getLocationInfo(const ValueDecl *VD, NameLen = getCharLength(SM, R); } else { if (VD->hasName()) { - // TODO: Handle special names - NameLen = VD->getBaseName().getIdentifier().getLength(); + NameLen = VD->getBaseName().userFacingName().size(); } else { NameLen = getCharLength(SM, VD->getLoc()); } diff --git a/lib/IDE/SyntaxModel.cpp b/lib/IDE/SyntaxModel.cpp index b6a2c1a3bea..3544bb60176 100644 --- a/lib/IDE/SyntaxModel.cpp +++ b/lib/IDE/SyntaxModel.cpp @@ -336,7 +336,7 @@ private: bool searchForURL(CharSourceRange Range); bool findFieldsInDocCommentLine(SyntaxNode Node); bool findFieldsInDocCommentBlock(SyntaxNode Node); - bool isVisitedBeforeInIfConfigStmt(ASTNode Node) { + bool isVisitedBeforeInIfConfig(ASTNode Node) { return VisitedNodesInsideIfConfig.count(Node) > 0; } }; @@ -438,7 +438,7 @@ void ModelASTWalker::visitSourceFile(SourceFile &SrcFile, } std::pair ModelASTWalker::walkToExprPre(Expr *E) { - if (isVisitedBeforeInIfConfigStmt(E)) + if (isVisitedBeforeInIfConfig(E)) return {false, E}; if (E->isImplicit()) @@ -556,7 +556,7 @@ void ModelASTWalker::handleStmtCondition(StmtCondition cond) { std::pair ModelASTWalker::walkToStmtPre(Stmt *S) { - if (isVisitedBeforeInIfConfigStmt(S)) { + if (isVisitedBeforeInIfConfig(S)) { return {false, S}; } auto addExprElem = [&](SyntaxStructureElementKind K, const Expr *Elem, @@ -699,39 +699,6 @@ std::pair ModelASTWalker::walkToStmtPre(Stmt *S) { pushStructureNode(SN, SW); } - } else if (auto ConfigS = dyn_cast(S)) { - for (auto &Clause : ConfigS->getClauses()) { - unsigned TokLen; - if (&Clause == &*ConfigS->getClauses().begin()) - TokLen = 3; // '#if' - else if (Clause.Cond == nullptr) - TokLen = 5; // '#else' - else - TokLen = 7; // '#elseif' - if (!passNonTokenNode({SyntaxNodeKind::BuildConfigKeyword, - CharSourceRange(Clause.Loc, TokLen) })) - return { false, nullptr }; - - if (Clause.Cond && !annotateIfConfigConditionIdentifiers(Clause.Cond)) - return { false, nullptr }; - - for (auto &Element : Clause.Elements) { - if (auto *E = Element.dyn_cast()) { - E->walk(*this); - } else if (auto *S = Element.dyn_cast()) { - S->walk(*this); - } else { - Element.get()->walk(*this); - } - VisitedNodesInsideIfConfig.insert(Element); - } - } - - if (!ConfigS->hadMissingEnd()) - if (!passNonTokenNode({ SyntaxNodeKind::BuildConfigKeyword, - CharSourceRange(ConfigS->getEndLoc(), 6/*'#endif'*/) })) - return { false, nullptr }; - } else if (auto *DeferS = dyn_cast(S)) { if (auto *FD = DeferS->getTempDecl()) { auto *RetS = FD->getBody()->walk(*this); @@ -752,7 +719,7 @@ Stmt *ModelASTWalker::walkToStmtPost(Stmt *S) { } bool ModelASTWalker::walkToDeclPre(Decl *D) { - if (isVisitedBeforeInIfConfigStmt(D)) + if (isVisitedBeforeInIfConfig(D)) return false; if (D->isImplicit()) return false; @@ -916,9 +883,16 @@ bool ModelASTWalker::walkToDeclPre(Decl *D) { if (Clause.Cond && !annotateIfConfigConditionIdentifiers(Clause.Cond)) return false; - for (auto *D : Clause.Elements) - if (D->walk(*this)) - return false; + for (auto &Element : Clause.Elements) { + if (auto *E = Element.dyn_cast()) { + E->walk(*this); + } else if (auto *S = Element.dyn_cast()) { + S->walk(*this); + } else { + Element.get()->walk(*this); + } + VisitedNodesInsideIfConfig.insert(Element); + } } if (!ConfigD->hadMissingEnd()) @@ -1038,9 +1012,9 @@ public: return { true, E }; if (DRE->getRefKind() != DeclRefKind::Ordinary) return { true, E }; - // TODO: Handle special names - if (!Fn(CharSourceRange(DRE->getSourceRange().Start, - DRE->getName().getBaseIdentifier().getLength()))) + if (!Fn(CharSourceRange( + DRE->getSourceRange().Start, + DRE->getName().getBaseName().userFacingName().size()))) return { false, nullptr }; } return { true, E }; diff --git a/lib/IDE/TypeReconstruction.cpp b/lib/IDE/TypeReconstruction.cpp index 50ed2ebc9cd..209a135a852 100644 --- a/lib/IDE/TypeReconstruction.cpp +++ b/lib/IDE/TypeReconstruction.cpp @@ -695,7 +695,8 @@ static void VisitNodeAddressor( // and they bear no connection to their original variable at the interface // level CanFunctionType swift_can_func_type = - CanFunctionType::get(ast->TheEmptyTupleType, ast->TheRawPointerType); + CanFunctionType::get({}, ast->TheRawPointerType, + AnyFunctionType::ExtInfo()); result._types.push_back(swift_can_func_type.getPointer()); } diff --git a/lib/IRGen/ConstantBuilder.h b/lib/IRGen/ConstantBuilder.h index c0c975e05f1..71eaa00711d 100644 --- a/lib/IRGen/ConstantBuilder.h +++ b/lib/IRGen/ConstantBuilder.h @@ -107,6 +107,14 @@ public: Size getNextOffsetFromGlobal() const { return Size(super::getNextOffsetFromGlobal().getQuantity()); } + + void addAlignmentPadding(Alignment align) { + auto misalignment = getNextOffsetFromGlobal() % IGM().getPointerAlignment(); + if (misalignment != Size(0)) + add(llvm::ConstantAggregateZero::get( + llvm::ArrayType::get(IGM().Int8Ty, + align.getValue() - misalignment.getValue()))); + } }; class ConstantArrayBuilder diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index f2a7ce5628d..c9e2ea4c065 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -365,7 +365,9 @@ NativeConventionSchema::getCoercionTypes( packed = true; elts.push_back(type); expandedTyIndicesMap.push_back(idx - 1); - lastEnd = end; + lastEnd = begin + clang::CharUnits::fromQuantity( + IGM.DataLayout.getTypeAllocSize(type)); + assert(end <= lastEnd); }); auto *coercionType = llvm::StructType::get(ctx, elts, packed); @@ -402,7 +404,9 @@ NativeConventionSchema::getCoercionTypes( packed = true; elts.push_back(type); expandedTyIndicesMap.push_back(idx - 1); - lastEnd = end; + lastEnd = begin + clang::CharUnits::fromQuantity( + IGM.DataLayout.getTypeAllocSize(type)); + assert(end <= lastEnd); }); auto *overlappedCoercionType = llvm::StructType::get(ctx, elts, packed); return {coercionType, overlappedCoercionType}; diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp index c30f6dda78b..56e74029ef6 100644 --- a/lib/IRGen/GenClass.cpp +++ b/lib/IRGen/GenClass.cpp @@ -181,14 +181,30 @@ namespace { // If not, we can have to access stored properties through the field // offset vector in the instantiated type metadata. bool ClassHasConcreteLayout = true; - + public: - ClassLayoutBuilder(IRGenModule &IGM, SILType classType) + ClassLayoutBuilder(IRGenModule &IGM, SILType classType, + ReferenceCounting refcounting) : StructLayoutBuilder(IGM) { // Start by adding a heap header. - addHeapHeader(); - + switch (refcounting) { + case swift::irgen::ReferenceCounting::Native: + // For native classes, place a full object header. + addHeapHeader(); + break; + case swift::irgen::ReferenceCounting::ObjC: + // For ObjC-inheriting classes, we don't reliably know the size of the + // base class, but NSObject only has an `isa` pointer at most. + addNSObjectHeader(); + break; + case swift::irgen::ReferenceCounting::Block: + case swift::irgen::ReferenceCounting::Unknown: + case swift::irgen::ReferenceCounting::Bridge: + case swift::irgen::ReferenceCounting::Error: + llvm_unreachable("not a class refcounting kind"); + } + // Next, add the fields for the given class. auto theClass = classType.getClassOrBoundGenericClass(); assert(theClass); @@ -382,7 +398,7 @@ void ClassTypeInfo::generateLayout(IRGenModule &IGM, SILType classType) const { "already generated layout"); // Add the heap header. - ClassLayoutBuilder builder(IGM, classType); + ClassLayoutBuilder builder(IGM, classType, Refcount); // generateLayout can call itself recursively in order to compute a layout // for the abstract type. If classType shares an exemplar types with the @@ -409,7 +425,8 @@ void ClassTypeInfo::generateLayout(IRGenModule &IGM, SILType classType) const { const StructLayout & ClassTypeInfo::getLayout(IRGenModule &IGM, SILType classType) const { // Return the cached layout if available. - if (Layout) return *Layout; + if (Layout) + return *Layout; generateLayout(IGM, classType); return *Layout; @@ -489,7 +506,20 @@ irgen::tryEmitConstantClassFragilePhysicalMemberOffset(IRGenModule &IGM, } } +unsigned +irgen::getClassFieldIndex(IRGenModule &IGM, SILType baseType, VarDecl *field) { + auto &baseClassTI = IGM.getTypeInfo(baseType).as(); + auto &classLayout = baseClassTI.getClassLayout(IGM, baseType); + return classLayout.getFieldIndex(field); +} +FieldAccess +irgen::getClassFieldAccess(IRGenModule &IGM, SILType baseType, VarDecl *field) { + auto &baseClassTI = IGM.getTypeInfo(baseType).as(); + auto &classLayout = baseClassTI.getClassLayout(IGM, baseType); + unsigned fieldIndex = classLayout.getFieldIndex(field); + return classLayout.AllFieldAccesses[fieldIndex]; +} OwnedAddress irgen::projectPhysicalClassMemberAddress(IRGenFunction &IGF, llvm::Value *base, diff --git a/lib/IRGen/GenClass.h b/lib/IRGen/GenClass.h index 505f51287bb..6656897c460 100644 --- a/lib/IRGen/GenClass.h +++ b/lib/IRGen/GenClass.h @@ -48,6 +48,7 @@ namespace irgen { enum class ReferenceCounting : unsigned char; enum class IsaEncoding : unsigned char; enum class ClassDeallocationKind : unsigned char; + enum class FieldAccess : uint8_t; OwnedAddress projectPhysicalClassMemberAddress(IRGenFunction &IGF, llvm::Value *base, @@ -138,6 +139,14 @@ namespace irgen { tryEmitConstantClassFragilePhysicalMemberOffset(IRGenModule &IGM, SILType baseType, VarDecl *field); + + unsigned getClassFieldIndex(IRGenModule &IGM, + SILType baseType, + VarDecl *field); + + FieldAccess getClassFieldAccess(IRGenModule &IGM, + SILType baseType, + VarDecl *field); /// What reference counting mechanism does a class-like type use? ReferenceCounting getReferenceCountingForType(IRGenModule &IGM, diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index a1a6e418670..66395127c48 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -959,9 +959,9 @@ void IRGenerator::emitEagerClassInitialization() { llvm::FunctionType::get(IGM->VoidTy, false), llvm::GlobalValue::PrivateLinkage, "_swift_eager_class_initialization"); + IGM->Module.getFunctionList().push_back(RegisterFn); IRGenFunction RegisterIGF(*IGM, RegisterFn); RegisterFn->setAttributes(IGM->constructInitialAttributes()); - IGM->Module.getFunctionList().push_back(RegisterFn); RegisterFn->setCallingConv(IGM->DefaultCC); for (ClassDecl *CD : ClassesForEagerInitialization) { diff --git a/lib/IRGen/GenEnum.cpp b/lib/IRGen/GenEnum.cpp index 85cfb9c5eb8..0f98032967e 100644 --- a/lib/IRGen/GenEnum.cpp +++ b/lib/IRGen/GenEnum.cpp @@ -2921,7 +2921,7 @@ namespace { llvm::Function *emitConsumeEnumFunction(IRGenModule &IGM, EnumDecl *theEnum) { IRGenMangler Mangler; - std::string name = Mangler.mangleOutlinedCopyFunction(theEnum); + std::string name = Mangler.mangleOutlinedConsumeFunction(theEnum); auto func = createOutlineLLVMFunction(IGM, name, PayloadTypesAndTagType); IRGenFunction IGF(IGM, func); diff --git a/lib/IRGen/GenHeap.cpp b/lib/IRGen/GenHeap.cpp index a6fd29babff..45587728fef 100644 --- a/lib/IRGen/GenHeap.cpp +++ b/lib/IRGen/GenHeap.cpp @@ -1430,7 +1430,7 @@ public: allocate(IRGenFunction &IGF, SILType boxedType, GenericEnvironment *env, const llvm::Twine &name) const override { return OwnedAddress(IGF.getTypeInfo(boxedType).getUndefAddress(), - IGF.IGM.RefCountedNull); + IGF.emitAllocEmptyBoxCall()); } void @@ -1584,7 +1584,11 @@ const TypeInfo *TypeConverter::convertBoxType(SILBoxType *T) { // For fixed-sized types, we can emit concrete box metadata. auto &fixedTI = cast(eltTI); - // For empty types, we don't really need to allocate anything. + // Because we assume in enum's that payloads with a Builtin.NativeObject which + // is also the type for indirect enum cases have extra inhabitants of pointers + // we can't have a nil pointer as a representation for an empty box type -- + // nil conflicts with the extra inhabitants. We return a static singleton + // empty box object instead. if (fixedTI.isKnownEmpty(ResilienceExpansion::Maximal)) { if (!EmptyBoxTI) EmptyBoxTI = new EmptyBoxTypeInfo(IGM); diff --git a/lib/IRGen/GenKeyPath.cpp b/lib/IRGen/GenKeyPath.cpp index 4bb44295749..d9f3c709f9e 100644 --- a/lib/IRGen/GenKeyPath.cpp +++ b/lib/IRGen/GenKeyPath.cpp @@ -25,6 +25,7 @@ #include "IRGenFunction.h" #include "IRGenModule.h" #include "ProtocolInfo.h" +#include "StructLayout.h" #include "llvm/ADT/SetVector.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILLocation.h" @@ -122,7 +123,7 @@ IRGenModule::getAddrOfKeyPathPattern(KeyPathPattern *pattern, fields.add(emitMetadataGenerator(rootTy)); fields.add(emitMetadataGenerator(valueTy)); - // TODO: 32-bit still has a padding word + // TODO: 32-bit heap object header still has an extra word if (SizeTy == Int32Ty) { fields.addInt32(0); } @@ -154,73 +155,31 @@ IRGenModule::getAddrOfKeyPathPattern(KeyPathPattern *pattern, // Leave a placeholder for the buffer header, since we need to know the full // buffer size to fill it in. auto headerPlaceholder = fields.addPlaceholderWithSize(Int32Ty); + fields.addAlignmentPadding(getPointerAlignment()); auto startOfKeyPathBuffer = fields.getNextOffsetFromGlobal(); // Build out the components. auto baseTy = rootTy; - auto getPropertyOffsetOrIndirectOffset - = [&](SILType loweredBaseTy, VarDecl *property) - -> std::pair { - llvm::Constant *offset; - bool isResolved; - bool isStruct; - if (loweredBaseTy.getStructOrBoundGenericStruct()) { - offset = emitPhysicalStructMemberFixedOffset(*this, - loweredBaseTy, - property); - isStruct = true; - } else if (loweredBaseTy.getClassOrBoundGenericClass()) { - offset = tryEmitConstantClassFragilePhysicalMemberOffset(*this, - loweredBaseTy, - property); - isStruct = false; - } else { - llvm_unreachable("property of non-struct, non-class?!"); - } - - // If the offset isn't fixed, try instead to get the field offset vector - // offset for the field to look it up dynamically. - isResolved = offset != nullptr; - if (!isResolved) { - if (isStruct) { - offset = emitPhysicalStructMemberOffsetOfFieldOffset( - *this, loweredBaseTy, property); - assert(offset && "field is neither fixed-offset nor in offset vector"); - } else { - auto offsetValue = getClassFieldOffset(*this, - loweredBaseTy.getClassOrBoundGenericClass(), - property); - offset = llvm::ConstantInt::get(Int32Ty, offsetValue.getValue()); - } - } - - return {offset, isResolved}; - }; + auto assertPointerAlignment = [&]{ + assert(fields.getNextOffsetFromGlobal() % getPointerAlignment() == Size(0) + && "must be pointer-aligned here"); + }; for (unsigned i : indices(pattern->getComponents())) { + assertPointerAlignment(); SILType loweredBaseTy; Lowering::GenericContextScope scope(getSILTypes(), pattern->getGenericSignature()); loweredBaseTy = getLoweredType(AbstractionPattern::getOpaque(), baseTy->getLValueOrInOutObjectType()); - auto &component = pattern->getComponents()[i]; switch (auto kind = component.getKind()) { case KeyPathPatternComponent::Kind::StoredProperty: { - // Try to get a constant offset if we can. auto property = cast(component.getStoredPropertyDecl()); - llvm::Constant *offset; - bool isResolved; - std::tie(offset, isResolved) - = getPropertyOffsetOrIndirectOffset(loweredBaseTy, property); - offset = llvm::ConstantExpr::getTruncOrBitCast(offset, Int32Ty); - bool isStruct = (bool)loweredBaseTy.getStructOrBoundGenericStruct(); - // If the projection is a statically known integer, try to pack it into - // the key path payload. - if (isResolved) { + auto addFixedOffset = [&](bool isStruct, llvm::Constant *offset) { if (auto offsetInt = dyn_cast_or_null(offset)) { auto offsetValue = offsetInt->getValue().getZExtValue(); if (KeyPathComponentHeader::offsetCanBeInline(offsetValue)) { @@ -228,28 +187,87 @@ IRGenModule::getAddrOfKeyPathPattern(KeyPathPattern *pattern, ? KeyPathComponentHeader::forStructComponentWithInlineOffset(offsetValue) : KeyPathComponentHeader::forClassComponentWithInlineOffset(offsetValue); fields.addInt32(header.getData()); - break; + return; } } - auto header = isStruct ? KeyPathComponentHeader::forStructComponentWithOutOfLineOffset() : KeyPathComponentHeader::forClassComponentWithOutOfLineOffset(); fields.addInt32(header.getData()); + fields.add(llvm::ConstantExpr::getTruncOrBitCast(offset, Int32Ty)); + }; + + // For a struct stored property, we may know the fixed offset of the field, + // or we may need to fetch it out of the type's metadata at instantiation + // time. + if (loweredBaseTy.getStructOrBoundGenericStruct()) { + if (auto offset = emitPhysicalStructMemberFixedOffset(*this, + loweredBaseTy, + property)) { + // We have a known constant fixed offset. + addFixedOffset(/*struct*/ true, offset); + break; + } - fields.add(offset); - } else { - // Otherwise, stash the offset of the field offset within the metadata - // object, so we can pull it out at instantiation time. - // TODO: We'll also need a way to handle resilient field offsets, once - // field offset vectors no longer cover all fields in the type. - KeyPathComponentHeader header = isStruct - ? KeyPathComponentHeader::forStructComponentWithUnresolvedOffset() - : KeyPathComponentHeader::forClassComponentWithUnresolvedOffset(); + // If the offset isn't fixed, try instead to get the field offset out + // of the type metadata at instantiation time. + auto fieldOffset = emitPhysicalStructMemberOffsetOfFieldOffset( + *this, loweredBaseTy, property); + auto header = KeyPathComponentHeader::forStructComponentWithUnresolvedFieldOffset(); fields.addInt32(header.getData()); - fields.add(offset); + fields.add(llvm::ConstantExpr::getTruncOrBitCast(fieldOffset, + Int32Ty)); + break; } - break; + + // For a class, we may know the fixed offset of a field at compile time, + // or we may need to fetch it at instantiation time. Depending on the + // ObjC-ness and resilience of the class hierarchy, there might be a few + // different ways we need to go about this. + if (loweredBaseTy.getClassOrBoundGenericClass()) { + switch (getClassFieldAccess(*this, loweredBaseTy, property)) { + case FieldAccess::ConstantDirect: { + // Known constant fixed offset. + auto offset = tryEmitConstantClassFragilePhysicalMemberOffset(*this, + loweredBaseTy, + property); + assert(offset && "no constant offset for ConstantDirect field?!"); + addFixedOffset(/*struct*/ false, offset); + break; + } + case FieldAccess::NonConstantDirect: { + // A constant offset that's determined at class realization time. + // We have to load the offset from a global ivar. + auto header = + KeyPathComponentHeader::forClassComponentWithUnresolvedIndirectOffset(); + fields.addInt32(header.getData()); + fields.addAlignmentPadding(getPointerAlignment()); + auto offsetVar = getAddrOfFieldOffset(property, /*indirect*/ false, + NotForDefinition); + fields.add(cast(offsetVar.getAddress())); + break; + } + case FieldAccess::ConstantIndirect: { + // An offset that depends on the instance's generic parameterization, + // but whose field offset is at a known vtable offset. + auto header = + KeyPathComponentHeader::forClassComponentWithUnresolvedFieldOffset(); + fields.addInt32(header.getData()); + auto fieldOffset = + getClassFieldOffset(*this, loweredBaseTy.getClassOrBoundGenericClass(), + property); + fields.addInt32(fieldOffset.getValue()); + break; + } + case FieldAccess::NonConstantIndirect: + // An offset that depends on the instance's generic parameterization, + // whose vtable offset is also unknown. + // TODO: This doesn't happen until class resilience is enabled. + llvm_unreachable("not implemented"); + } + break; + } + llvm_unreachable("not struct or class"); } case KeyPathPatternComponent::Kind::GettableProperty: case KeyPathPatternComponent::Kind::SettableProperty: { @@ -306,10 +324,36 @@ IRGenModule::getAddrOfKeyPathPattern(KeyPathPattern *pattern, break; } case KeyPathPatternComponent::ComputedPropertyId::Property: - idKind = KeyPathComponentHeader::StoredPropertyOffset; - std::tie(idValue, idResolved) = - getPropertyOffsetOrIndirectOffset(loweredBaseTy, id.getProperty()); - idValue = llvm::ConstantExpr::getZExtOrBitCast(idValue, SizeTy); + // Use the index of the stored property within the aggregate to key + // the property. + auto property = id.getProperty(); + idKind = KeyPathComponentHeader::StoredPropertyIndex; + if (baseTy->getStructOrBoundGenericStruct()) { + idResolved = true; + idValue = llvm::ConstantInt::get(SizeTy, + getPhysicalStructFieldIndex(*this, + SILType::getPrimitiveAddressType(baseTy), property)); + } else if (baseTy->getClassOrBoundGenericClass()) { + // TODO: This field index would require runtime resolution with Swift + // native class resilience. We never directly access ObjC-imported + // ivars so we can disregard ObjC ivar resilience for this computation + // and start counting at the Swift native root. + switch (getClassFieldAccess(*this, loweredBaseTy, property)) { + case FieldAccess::ConstantDirect: + case FieldAccess::ConstantIndirect: + case FieldAccess::NonConstantDirect: + idResolved = true; + idValue = llvm::ConstantInt::get(SizeTy, + getClassFieldIndex(*this, + SILType::getPrimitiveAddressType(baseTy), property)); + break; + case FieldAccess::NonConstantIndirect: + llvm_unreachable("not implemented"); + } + + } else { + llvm_unreachable("neither struct nor class"); + } break; } @@ -317,6 +361,7 @@ IRGenModule::getAddrOfKeyPathPattern(KeyPathPattern *pattern, idKind, !isInstantiableInPlace, idResolved); fields.addInt32(header.getData()); + fields.addAlignmentPadding(getPointerAlignment()); fields.add(idValue); if (isInstantiableInPlace) { @@ -335,11 +380,22 @@ IRGenModule::getAddrOfKeyPathPattern(KeyPathPattern *pattern, "generic computed key paths"); return llvm::UndefValue::get(Int8PtrTy); } + break; } + case KeyPathPatternComponent::Kind::OptionalChain: + fields.addInt32(KeyPathComponentHeader::forOptionalChain().getData()); + break; + case KeyPathPatternComponent::Kind::OptionalForce: + fields.addInt32(KeyPathComponentHeader::forOptionalForce().getData()); + break; + case KeyPathPatternComponent::Kind::OptionalWrap: + fields.addInt32(KeyPathComponentHeader::forOptionalWrap().getData()); + break; } // For all but the last component, we pack in the type of the component. if (i + 1 != pattern->getComponents().size()) { + fields.addAlignmentPadding(getPointerAlignment()); fields.add(emitMetadataGenerator(component.getComponentType())); } baseTy = component.getComponentType(); diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 50ce8286bb6..33d6eb1f76a 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -1692,8 +1692,9 @@ namespace { case SILFunctionType::Representation::Thick: // All function types look like () -> (). // FIXME: It'd be nice not to have to call through the runtime here. - return IGF.emitTypeMetadataRef(CanFunctionType::get(C.TheEmptyTupleType, - C.TheEmptyTupleType)); + return IGF.emitTypeMetadataRef( + CanFunctionType::get({ }, C.TheEmptyTupleType, + AnyFunctionType::ExtInfo())); case SILFunctionType::Representation::Block: // All block types look like Builtin.UnknownObject. return emitDirectMetadataRef(C.TheUnknownObjectType); @@ -1876,7 +1877,8 @@ namespace { case SILFunctionType::Representation::Thick: // All function types look like () -> (). return emitFromValueWitnessTable( - CanFunctionType::get(C.TheEmptyTupleType, C.TheEmptyTupleType)); + CanFunctionType::get({ }, C.TheEmptyTupleType, + AnyFunctionType::ExtInfo())); case SILFunctionType::Representation::Block: // All block types look like Builtin.UnknownObject. return emitFromValueWitnessTable(C.TheUnknownObjectType); diff --git a/lib/IRGen/GenReflection.cpp b/lib/IRGen/GenReflection.cpp index 390767acc61..84b3c1e1ca5 100644 --- a/lib/IRGen/GenReflection.cpp +++ b/lib/IRGen/GenReflection.cpp @@ -340,7 +340,8 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder { } if (IGM.IRGen.Opts.EnableReflectionNames) { - auto fieldName = IGM.getAddrOfFieldName(value->getNameStr()); + auto name = value->getBaseName().getIdentifier().str(); + auto fieldName = IGM.getAddrOfFieldName(name); B.addRelativeAddress(fieldName); } else { B.addInt32(0); @@ -927,8 +928,7 @@ void IRGenModule::emitBuiltinReflectionMetadata() { // extra inhabitants as these. But maybe it's best not to codify // that in the ABI anyway. CanType thinFunction = CanFunctionType::get( - TupleType::getEmpty(Context), - TupleType::getEmpty(Context), + { }, Context.TheEmptyTupleType, AnyFunctionType::ExtInfo().withRepresentation( FunctionTypeRepresentation::Thin)); BuiltinTypes.insert(thinFunction); diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp index 99fb00f1e6b..a89d79d2a82 100644 --- a/lib/IRGen/IRGen.cpp +++ b/lib/IRGen/IRGen.cpp @@ -150,8 +150,6 @@ void setModuleFlags(IRGenModule &IGM) { void swift::performLLVMOptimizations(IRGenOptions &Opts, llvm::Module *Module, llvm::TargetMachine *TargetMachine) { - SharedTimer timer("LLVM optimization"); - // Set up a pipeline. PassManagerBuilderWrapper PMBuilder(Opts); @@ -467,10 +465,8 @@ bool swift::performLLVM(IRGenOptions &Opts, DiagnosticEngine *Diags, } } - { - SharedTimer timer("LLVM output"); - EmitPasses.run(*Module); - } + EmitPasses.run(*Module); + if (Stats && RawOS.hasValue()) { if (DiagMutex) DiagMutex->lock(); @@ -788,6 +784,8 @@ static std::unique_ptr performIRGeneration(IRGenOptions &Opts, if (outModuleHash) { *outModuleHash = IGM.ModuleHash; } else { + SharedTimer timer("LLVM pipeline"); + // Since no out module hash was set, we need to performLLVM. if (performLLVM(Opts, &IGM.Context.Diags, nullptr, IGM.ModuleHash, IGM.getModule(), IGM.TargetMachine.get(), @@ -1008,6 +1006,8 @@ static void performParallelIRGeneration(IRGenOptions &Opts, // Bail out if there are any errors. if (Ctx.hadError()) return; + SharedTimer timer("LLVM pipeline"); + std::vector Threads; llvm::sys::Mutex DiagMutex; diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp index 5676f97a237..1c8f443b2ab 100644 --- a/lib/IRGen/IRGenDebugInfo.cpp +++ b/lib/IRGen/IRGenDebugInfo.cpp @@ -400,7 +400,9 @@ private: } SmallVector Buf; - StringRef Name = (VD->getName().str() + Twine(Kind)).toStringRef(Buf); + // TODO: Handle special names + StringRef Name = (VD->getBaseName().getIdentifier().str() + + Twine(Kind)).toStringRef(Buf); return BumpAllocatedString(Name); } diff --git a/lib/IRGen/IRGenFunction.cpp b/lib/IRGen/IRGenFunction.cpp index e6a98b171d0..7162aeda58a 100644 --- a/lib/IRGen/IRGenFunction.cpp +++ b/lib/IRGen/IRGenFunction.cpp @@ -208,6 +208,20 @@ llvm::Value *IRGenFunction::emitProjectBoxCall(llvm::Value *box, return call; } +llvm::Value *IRGenFunction::emitAllocEmptyBoxCall() { + llvm::Attribute::AttrKind attrKinds[] = { + llvm::Attribute::NoUnwind, + }; + auto attrs = llvm::AttributeSet::get(IGM.LLVMContext, + llvm::AttributeSet::FunctionIndex, + attrKinds); + llvm::CallInst *call = + Builder.CreateCall(IGM.getAllocEmptyBoxFn(), {}); + call->setCallingConv(IGM.DefaultCC); + call->setAttributes(attrs); + return call; +} + static void emitDeallocatingCall(IRGenFunction &IGF, llvm::Constant *fn, std::initializer_list args) { auto cc = IGF.IGM.DefaultCC; diff --git a/lib/IRGen/IRGenFunction.h b/lib/IRGen/IRGenFunction.h index d28a0926b9d..ab552dcbd33 100644 --- a/lib/IRGen/IRGenFunction.h +++ b/lib/IRGen/IRGenFunction.h @@ -188,6 +188,8 @@ public: llvm::Value *emitProjectBoxCall(llvm::Value *box, llvm::Value *typeMetadata); + llvm::Value *emitAllocEmptyBoxCall(); + // Emit a reference to the canonical type metadata record for the given AST // type. This can be used to identify the type at runtime. For types with // abstraction difference, the metadata contains the layout information for diff --git a/lib/IRGen/LoadableByAddress.cpp b/lib/IRGen/LoadableByAddress.cpp index dc23a6b9197..d1bba45a907 100644 --- a/lib/IRGen/LoadableByAddress.cpp +++ b/lib/IRGen/LoadableByAddress.cpp @@ -1344,6 +1344,24 @@ static void castTupleInstr(SILInstruction *instr, IRGenModule &Mod) { castInstr->setOperand(0, instr); } +static SILValue createCopyOfEnum(StructLoweringState &pass, + SwitchEnumInst *orig) { + auto value = orig->getOperand(); + SILBuilder allocBuilder(pass.F->begin()->begin()); + auto *allocInstr = + allocBuilder.createAllocStack(getLocForValue(value), value->getType()); + + SILBuilder copyBuilder(orig); + createOutlinedCopyCall(copyBuilder, value, allocInstr, pass); + + for (TermInst *termInst : pass.returnInsts) { + SILBuilder deallocBuilder(termInst); + deallocBuilder.createDeallocStack(allocInstr->getLoc(), allocInstr); + } + + return allocInstr; +} + static void rewriteFunction(StructLoweringState &pass, LoadableStorageAllocation &allocator) { @@ -1357,6 +1375,9 @@ static void rewriteFunction(StructLoweringState &pass, do { while (!pass.switchEnumInstsToMod.empty()) { auto *instr = pass.switchEnumInstsToMod.pop_back_val(); + /* unchecked_take_enum_data_addr can be destructive. + * work on a copy instead of the original enum */ + auto copiedValue = createCopyOfEnum(pass, instr); SILBuilder enumBuilder(instr); unsigned numOfCases = instr->getNumCases(); SmallVector, 16> caseBBs; @@ -1374,8 +1395,7 @@ static void rewriteFunction(StructLoweringState &pass, } auto *newArg = argBuilder.createUncheckedTakeEnumDataAddr( - instr->getLoc(), instr->getOperand(), decl, - newSILType.getAddressType()); + instr->getLoc(), copiedValue, decl, newSILType.getAddressType()); arg->replaceAllUsesWith(newArg); currBB->eraseArgument(0); @@ -1401,7 +1421,7 @@ static void rewriteFunction(StructLoweringState &pass, SILBasicBlock *defaultBB = instr->hasDefault() ? instr->getDefaultBB() : nullptr; auto *newInstr = enumBuilder.createSwitchEnumAddr( - instr->getLoc(), instr->getOperand(), defaultBB, caseBBs); + instr->getLoc(), copiedValue, defaultBB, caseBBs); instr->replaceAllUsesWith(newInstr); instr->getParent()->erase(instr); } diff --git a/lib/IRGen/StructLayout.cpp b/lib/IRGen/StructLayout.cpp index 1b6f66c75ac..82b18620b90 100644 --- a/lib/IRGen/StructLayout.cpp +++ b/lib/IRGen/StructLayout.cpp @@ -189,6 +189,13 @@ void StructLayoutBuilder::addHeapHeader() { StructFields.push_back(IGM.RefCountedStructTy); } +void StructLayoutBuilder::addNSObjectHeader() { + assert(StructFields.empty() && "adding heap header at a non-zero offset"); + CurSize = IGM.getPointerSize(); + CurAlignment = IGM.getPointerAlignment(); + StructFields.push_back(IGM.ObjCClassPtrTy); +} + bool StructLayoutBuilder::addFields(llvm::MutableArrayRef elts, LayoutStrategy strategy) { // Track whether we've added any storage to our layout. diff --git a/lib/IRGen/StructLayout.h b/lib/IRGen/StructLayout.h index 1b59c55f271..4d058d2f21d 100644 --- a/lib/IRGen/StructLayout.h +++ b/lib/IRGen/StructLayout.h @@ -233,9 +233,12 @@ public: StructLayoutBuilder(IRGenModule &IGM) : IGM(IGM) {} /// Add a swift heap header to the layout. This must be the first - /// call to the layout. + /// thing added to the layout. void addHeapHeader(); - + /// Add the NSObject object header to the layout. This must be the first + /// thing added to the layout. + void addNSObjectHeader(); + /// Add a number of fields to the layout. The field layouts need /// only have the TypeInfo set; the rest will be filled out. /// diff --git a/lib/Index/Index.cpp b/lib/Index/Index.cpp index 706a158166d..479b3ed72b6 100644 --- a/lib/Index/Index.cpp +++ b/lib/Index/Index.cpp @@ -263,25 +263,6 @@ private: if (auto *VD = dyn_cast(D)) { if (!report(VD)) return false; - if (auto *SD = dyn_cast(VD)) { - // Avoid indexing the indices, only walk the getter/setter. - if (SD->getGetter()) - if (SourceEntityWalker::walk(cast(SD->getGetter()))) - return false; - if (SD->getSetter()) - if (SourceEntityWalker::walk(cast(SD->getSetter()))) - return false; - if (SD->hasAddressors()) { - if (auto FD = SD->getAddressor()) - SourceEntityWalker::walk(cast(FD)); - if (Cancelled) - return false; - if (auto FD = SD->getMutableAddressor()) - SourceEntityWalker::walk(cast(FD)); - } - walkToDeclPost(D); - return false; // already walked what we needed. - } } if (auto *ED = dyn_cast(D)) return reportExtension(ED); @@ -885,12 +866,13 @@ bool IndexSwiftASTWalker::reportExtension(ExtensionDecl *D) { bool IndexSwiftASTWalker::report(ValueDecl *D) { if (startEntityDecl(D)) { // Pass accessors. - if (auto VarD = dyn_cast(D)) { + if (auto StoreD = dyn_cast(D)) { auto isNullOrImplicit = [](const Decl *D) -> bool { return !D || D->isImplicit(); }; - if (isNullOrImplicit(VarD->getGetter()) && - isNullOrImplicit(VarD->getSetter())) { + if (isa(D) && isNullOrImplicit(StoreD->getGetter()) && + isNullOrImplicit(StoreD->getSetter())) { + auto VarD = cast(D); // No actual getter or setter, pass 'pseudo' accessors. // We create accessor entities so we can implement the functionality // of libclang, which reports implicit method property accessor @@ -903,31 +885,31 @@ bool IndexSwiftASTWalker::report(ValueDecl *D) { if (!reportPseudoSetterDecl(VarD)) return false; } else { - if (auto FD = VarD->getGetter()) + if (auto FD = StoreD->getGetter()) SourceEntityWalker::walk(cast(FD)); if (Cancelled) return false; - if (auto FD = VarD->getSetter()) + if (auto FD = StoreD->getSetter()) SourceEntityWalker::walk(cast(FD)); if (Cancelled) return false; } - if (VarD->hasObservers()) { - if (auto FD = VarD->getWillSetFunc()) + if (StoreD->hasObservers()) { + if (auto FD = StoreD->getWillSetFunc()) SourceEntityWalker::walk(cast(FD)); if (Cancelled) return false; - if (auto FD = VarD->getDidSetFunc()) + if (auto FD = StoreD->getDidSetFunc()) SourceEntityWalker::walk(cast(FD)); if (Cancelled) return false; } - if (VarD->hasAddressors()) { - if (auto FD = VarD->getAddressor()) + if (StoreD->hasAddressors()) { + if (auto FD = StoreD->getAddressor()) SourceEntityWalker::walk(cast(FD)); if (Cancelled) return false; - if (auto FD = VarD->getMutableAddressor()) + if (auto FD = StoreD->getMutableAddressor()) SourceEntityWalker::walk(cast(FD)); } } else if (auto NTD = dyn_cast(D)) { diff --git a/lib/Migrator/APIDiffMigratorPass.cpp b/lib/Migrator/APIDiffMigratorPass.cpp index 915b92f64fd..6f5decc7159 100644 --- a/lib/Migrator/APIDiffMigratorPass.cpp +++ b/lib/Migrator/APIDiffMigratorPass.cpp @@ -12,6 +12,7 @@ #include "swift/AST/USRGeneration.h" #include "swift/AST/ASTVisitor.h" +#include "swift/Basic/StringExtras.h" #include "swift/Frontend/Frontend.h" #include "swift/IDE/Utils.h" #include "swift/Index/Utils.h" @@ -168,9 +169,11 @@ public: // as their own index level if (T->getNumElements() == 1) { ParentIsOptional = false; - return visit(T->getElement(0)); + return visit(T->getElementType(0)); } - return handleParent(T, T->getElements()); + llvm::SmallVector Children; + T->getElementTypes(Children); + return handleParent(T, ArrayRef(Children)); } FoundResult visitFunctionTypeRepr(FunctionTypeRepr *T) { @@ -367,20 +370,26 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { } bool handleQualifiedReplacement(Expr* Call) { - if (auto *DSC = dyn_cast(Call)) { - if (auto FD = DSC->getFn()->getReferencedDecl().getDecl()) { - for (auto *I :getRelatedDiffItems(FD)) { - if (auto *Item = dyn_cast(I)) { - if (Item->Subkind == TypeMemberDiffItemSubKind:: - QualifiedReplacement) { - Editor.replace(Call->getSourceRange(), - (llvm::Twine(Item->newTypeName) + "." + - Item->getNewName().base()).str()); - return true; - } + auto handleDecl = [&](ValueDecl *VD, SourceRange ToReplace) { + for (auto *I: getRelatedDiffItems(VD)) { + if (auto *Item = dyn_cast(I)) { + if (Item->Subkind == TypeMemberDiffItemSubKind::QualifiedReplacement) { + Editor.replace(ToReplace, (llvm::Twine(Item->newTypeName) + "." + + Item->getNewName().base()).str()); + return true; } } } + return false; + }; + if (auto *DSC = dyn_cast(Call)) { + if (auto FD = DSC->getFn()->getReferencedDecl().getDecl()) { + if (handleDecl(FD, Call->getSourceRange())) + return true; + } + } else if (auto MRE = dyn_cast(Call)) { + if (handleDecl(MRE->getReferencedDecl().getDecl(), MRE->getSourceRange())) + return true; } return false; } @@ -605,8 +614,12 @@ struct APIDiffMigratorPass : public ASTMigratorPass, public SourceEntityWalker { Arg->getStartLoc().getAdvancedLoc(1)); // Replace "x.getY(" with "x.Y =". - Editor.replace(ReplaceRange, (llvm::Twine(Walker.Result.str(). - substr(3)) + " = ").str()); + auto Replacement = (llvm::Twine(Walker.Result.str() + .substr(3)) + " = ").str(); + SmallString<64> Scratch; + Editor.replace(ReplaceRange, + camel_case::toLowercaseInitialisms(Replacement, Scratch)); + // Remove ")" Editor.remove(CharSourceRange(SM, Arg->getEndLoc(), Arg->getEndLoc(). getAdvancedLoc(1))); diff --git a/lib/Migrator/Migrator.cpp b/lib/Migrator/Migrator.cpp index 43bc748b182..b02a7ddf4d1 100644 --- a/lib/Migrator/Migrator.cpp +++ b/lib/Migrator/Migrator.cpp @@ -53,9 +53,11 @@ bool migrator::updateCodeAndEmitRemap(CompilerInstance *Instance, } // Phase 2: Syntactic Transformations - auto FailedSyntacticPasses = M.performSyntacticPasses(); - if (FailedSyntacticPasses) { - return true; + if (Invocation.getLangOptions().EffectiveLanguageVersion[0] < 4) { + auto FailedSyntacticPasses = M.performSyntacticPasses(); + if (FailedSyntacticPasses) { + return true; + } } // Phase 3: Post Fix-it Passes diff --git a/lib/Migrator/README.md b/lib/Migrator/README.md index 321ae762833..baf7827dc53 100644 --- a/lib/Migrator/README.md +++ b/lib/Migrator/README.md @@ -48,7 +48,7 @@ Here are the passes: 2. AST Passes If the Pre-fix-it Pass was successful, or skipped because it was unnecessary, the - *AST Passes* run. These include: + *AST Passes* run if you are migrating *from before Swift 4*. These include: - API Diff Pass diff --git a/lib/Migrator/TupleSplatMigratorPass.cpp b/lib/Migrator/TupleSplatMigratorPass.cpp index d1ecc1e993e..8c774928c41 100644 --- a/lib/Migrator/TupleSplatMigratorPass.cpp +++ b/lib/Migrator/TupleSplatMigratorPass.cpp @@ -96,20 +96,10 @@ struct TupleSplatMigratorPass : public ASTMigratorPass, } unsigned ClosureArity = Closure->getParameters()->size(); - if (NativeArity == ClosureArity) + if (NativeArity <= ClosureArity) return false; ShorthandFinder Finder(Closure); - if (NativeArity == 1 && ClosureArity > 1) { - // Prepend $0. to existing references - Finder.forEachReference([this](Expr *Ref, ParamDecl* Def) { - if (auto *TE = dyn_cast(Ref)) - Ref = TE->getBase(); - SourceLoc AfterDollar = Ref->getStartLoc().getAdvancedLoc(1); - Editor.insert(AfterDollar, "0."); - }); - return true; - } if (ClosureArity == 1 && NativeArity > 1) { // Remove $0. from existing references or if it's only $0, replace it @@ -176,161 +166,8 @@ struct TupleSplatMigratorPass : public ASTMigratorPass, return true; }; - // Handles such kind of cases: - // \code - // func test(_: ((Int, Int)) -> ()) {} - // test({ (x,y) in }) - // \endcode - // This compiles fine in Swift 3 but Swift 4 complains with - // error: cannot convert value of type '(_, _) -> ()' to expected - // argument type '((Int, Int)) -> ()' - // - // It will fix the code to "test({ let (x,y) = $0; })". - // - auto handleTupleMapToClosureArgs = [&](const CallExpr *E) -> bool { - auto fnTy = E->getFn()->getType()->getAs(); - if (!fnTy) - return false; - auto fnTy2 = fnTy->getInput()->getAs(); - if (!fnTy2) { - // This may have been a tuple type of one element. - if (auto tuple = fnTy->getInput()->getAs()) { - if (tuple->getNumElements() == 1) { - fnTy2 = tuple->getElement(0).getType()->getAs(); - } - } - } - if (!fnTy2) { - return false; - } - auto parenT = dyn_cast(fnTy2->getInput().getPointer()); - if (!parenT) - return false; - auto tupleInFn = parenT->getAs(); - if (!tupleInFn) - return false; - if (!E->getArg()) - return false; - auto argE = E->getArg()->getSemanticsProvidingExpr(); - while (auto *ICE = dyn_cast(argE)) - argE = ICE->getSubExpr(); - argE = argE->getSemanticsProvidingExpr(); - auto closureE = dyn_cast(argE); - if (!closureE) { - if (auto *FCE = dyn_cast(argE)) { - closureE = dyn_cast(FCE->getSubExpr()); - } - } - if (!closureE) - return false; - if (closureE->getInLoc().isInvalid()) - return false; - auto paramList = closureE->getParameters(); - if (!paramList || - paramList->getLParenLoc().isInvalid() || paramList->getRParenLoc().isInvalid()) - return false; - if (paramList->size() != tupleInFn->getNumElements()) - return false; - if (paramList->size() == 0) - return false; - - auto hasParamListWithNoTypes = [&]() { - if (closureE->hasExplicitResultType()) - return false; - for (auto *param : *paramList) { - auto tyLoc = param->getTypeLoc(); - if (!tyLoc.isNull()) - return false; - } - return true; - }; - - if (hasParamListWithNoTypes()) { - // Simpler form depending on type inference. - // Change "(x, y) in " to "let (x, y) = $0;". - - Editor.insert(paramList->getLParenLoc(), "let "); - for (auto *param : *paramList) { - // If the argument list is like "(_ x, _ y)", remove the underscores. - if (param->getArgumentNameLoc().isValid()) { - Editor.remove(CharSourceRange(SM, param->getArgumentNameLoc(), - param->getNameLoc())); - } - // If the argument list has type annotations, remove them. - auto tyLoc = param->getTypeLoc(); - if (!tyLoc.isNull() && !tyLoc.getSourceRange().isInvalid()) { - auto nameRange = CharSourceRange(param->getNameLoc(), - param->getNameStr().size()); - auto tyRange = Lexer::getCharSourceRangeFromSourceRange(SM, - tyLoc.getSourceRange()); - Editor.remove(CharSourceRange(SM, nameRange.getEnd(), - tyRange.getEnd())); - } - } - - // If the original closure was a single expression without the need - // for a `return` statement, it needs one now, because we've added a new - // assignment statement just above. - if (closureE->hasSingleExpressionBody()) { - Editor.replaceToken(closureE->getInLoc(), "= $0; return"); - } else { - Editor.replaceToken(closureE->getInLoc(), "= $0;"); - } - - return true; - } - - // Includes types in the closure signature. The following will do a - // more complicated edit than the above: - // (x: Int, y: Int) -> Int in - // to - // (__val:(Int, Int)) -> Int in let (x,y) = __val; - - std::string paramListText; - { - llvm::raw_string_ostream OS(paramListText); - OS << "(__val:("; - for (size_t i = 0, e = paramList->size(); i != e; ++i) { - if (i != 0) - OS << ", "; - auto param = paramList->get(i); - auto tyLoc = param->getTypeLoc(); - if (!tyLoc.isNull() && !tyLoc.getSourceRange().isInvalid()) { - OS << SM.extractText( - Lexer::getCharSourceRangeFromSourceRange(SM, - tyLoc.getSourceRange())); - } else { - param->getType().print(OS); - } - } - OS << "))"; - } - std::string varBindText; - { - llvm::raw_string_ostream OS(varBindText); - OS << " let ("; - for (size_t i = 0, e = paramList->size(); i != e; ++i) { - if (i != 0) - OS << ","; - auto param = paramList->get(i); - OS << param->getNameStr(); - } - OS << ") = __val;"; - - if (closureE->hasSingleExpressionBody()) { - OS << " return"; - } - } - - Editor.replace(paramList->getSourceRange(), paramListText); - Editor.insertAfterToken(closureE->getInLoc(), varBindText); - return true; - }; - if (handleCallsToEmptyTuple(E)) return; - if (handleTupleMapToClosureArgs(E)) - return; } bool walkToExprPre(Expr *E) override { diff --git a/lib/Option/SanitizerOptions.cpp b/lib/Option/SanitizerOptions.cpp index ad4fbb57329..7f4abc73476 100644 --- a/lib/Option/SanitizerOptions.cpp +++ b/lib/Option/SanitizerOptions.cpp @@ -19,7 +19,12 @@ #include "swift/Basic/Platform.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticsFrontend.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" + using namespace swift; static StringRef toStringRef(const SanitizerKind kind) { @@ -95,9 +100,17 @@ llvm::SanitizerCoverageOptions swift::parseSanitizerCoverageArgValue( return opts; } +static bool isTSanSupported( + const llvm::Triple &Triple, + llvm::function_ref sanitizerRuntimeLibExists) { + + return Triple.isArch64Bit() && sanitizerRuntimeLibExists("tsan"); +} + SanitizerKind swift::parseSanitizerArgValues(const llvm::opt::Arg *A, - const llvm::Triple &Triple, - DiagnosticEngine &Diags) { + const llvm::Triple &Triple, + DiagnosticEngine &Diags, + llvm::function_ref sanitizerRuntimeLibExists) { SanitizerKind kind = SanitizerKind::None; // Find the sanitizer kind. @@ -137,11 +150,8 @@ SanitizerKind swift::parseSanitizerArgValues(const llvm::opt::Arg *A, (A->getOption().getPrefixedName() + toStringRef(kind)).toStringRef(b), Triple.getTriple()); } - // Thread Sanitizer only works on OS X and the simulators. It's only supported - // on 64 bit architectures. - if (kind == SanitizerKind::Thread && - (!(Triple.isMacOSX() || tripleIsAnySimulator(Triple)) || - !Triple.isArch64Bit())) { + if (kind == SanitizerKind::Thread + && !isTSanSupported(Triple, sanitizerRuntimeLibExists)) { SmallString<128> b; Diags.diagnose(SourceLoc(), diag::error_unsupported_opt_for_target, (A->getOption().getPrefixedName() + toStringRef(kind)).toStringRef(b), diff --git a/lib/Parse/Lexer.cpp b/lib/Parse/Lexer.cpp index 9170c23e07b..f659b6d6ac5 100644 --- a/lib/Parse/Lexer.cpp +++ b/lib/Parse/Lexer.cpp @@ -737,12 +737,12 @@ static bool rangeContainsPlaceholderEnd(const char *CurPtr, return false; } -RC Lexer::fullLex() { +RC Lexer::fullLex() { if (NextToken.isEscapedIdentifier()) { LeadingTrivia.push_back(syntax::TriviaPiece::backtick()); TrailingTrivia.push_front(syntax::TriviaPiece::backtick()); } - auto Result = syntax::TokenSyntax::make(NextToken.getKind(), + auto Result = syntax::RawTokenSyntax::make(NextToken.getKind(), OwnedString(NextToken.getText()).copy(), syntax::SourcePresence::Present, {LeadingTrivia}, {TrailingTrivia}); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 158f3ed005d..0d396c1ad8f 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2120,21 +2120,42 @@ void Parser::delayParseFromBeginningToHere(ParserPosition BeginParserPosition, ParserResult Parser::parseDecl(ParseDeclOptions Flags, llvm::function_ref Handler) { - if (Tok.isAny(tok::pound_sourceLocation, tok::pound_line)) { - auto LineDirectiveStatus = parseLineDirective(Tok.is(tok::pound_line)); - if (LineDirectiveStatus.isError()) - return LineDirectiveStatus; - // If success, go on. line directive never produce decls. - } if (Tok.is(tok::pound_if)) { - auto IfConfigResult = parseDeclIfConfig(Flags); + auto IfConfigResult = parseIfConfig( + [&](SmallVectorImpl &Decls, bool IsActive) { + Optional scope; + if (!IsActive) + scope.emplace(this, getScopeInfo().getCurrentScope()->getKind(), + /*inactiveConfigBlock=*/true); + + ParserStatus Status; + bool PreviousHadSemi = true; + while (Tok.isNot(tok::pound_else, tok::pound_endif, tok::pound_elseif, + tok::eof)) { + if (Tok.is(tok::r_brace)) { + diagnose(Tok.getLoc(), + diag::unexpected_rbrace_in_conditional_compilation_block); + // If we see '}', following declarations don't look like belong to + // the current decl context; skip them. + skipUntilConditionalBlockClose(); + break; + } + Status |= parseDeclItem(PreviousHadSemi, Flags, + [&](Decl *D) {Decls.emplace_back(D);}); + } + }); + if (auto ICD = IfConfigResult.getPtrOrNull()) { // The IfConfigDecl is ahead of its members in source order. Handler(ICD); // Copy the active members into the entries list. - for (auto activeMember : ICD->getActiveMembers()) { - Handler(activeMember); + for (auto activeMember : ICD->getActiveClauseElements()) { + auto *D = activeMember.get(); + if (isa(D)) + // Don't hoist nested '#if'. + continue; + Handler(D); } } return IfConfigResult; @@ -2739,6 +2760,23 @@ parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &Loc, P.checkForInputIncomplete(); + if (P.Tok.is(tok::integer_literal) || P.Tok.is(tok::floating_literal) || + (P.Tok.is(tok::unknown) && isdigit(P.Tok.getText()[0]))) { + // Using numbers for identifiers is a common error for beginners, so it's + // worth handling this in a special way. + P.diagnose(P.Tok, diag::number_cant_start_decl_name, DeclKindName); + + // Pretend this works as an identifier, which shouldn't be observable since + // actual uses of it will hit random other errors, e.g. `1()` won't be + // callable. + Result = P.Context.getIdentifier(P.Tok.getText()); + Loc = P.Tok.getLoc(); + P.consumeToken(); + + // We recovered, so this is a success. + return makeParserSuccess(); + } + if (P.Tok.isKeyword()) { P.diagnose(P.Tok, diag::keyword_cant_be_identifier, P.Tok.getText()); P.diagnose(P.Tok, diag::backticks_to_escape) @@ -2845,6 +2883,13 @@ ParserStatus Parser::parseDeclItem(bool &PreviousHadSemi, .fixItInsert(endOfPrevious, ";"); } + if (Tok.isAny(tok::pound_sourceLocation, tok::pound_line)) { + auto LineDirectiveStatus = parseLineDirective(Tok.is(tok::pound_line)); + if (LineDirectiveStatus.isError()) + skipUntilDeclRBrace(tok::semi, tok::pound_endif); + return LineDirectiveStatus; + } + auto Result = parseDecl(Options, handler); if (Result.isParseError()) skipUntilDeclRBrace(tok::semi, tok::pound_endif); @@ -3418,29 +3463,28 @@ static FuncDecl *createAccessorFunc(SourceLoc DeclLoc, ParameterList *param, // Non-static set/willSet/didSet/materializeForSet/mutableAddress // default to mutating. get/address default to // non-mutating. - if (!D->isStatic()) { - switch (Kind) { - case AccessorKind::IsAddressor: - D->setAddressorKind(addressorKind); - break; + switch (Kind) { + case AccessorKind::IsAddressor: + D->setAddressorKind(addressorKind); + break; - case AccessorKind::IsGetter: - break; + case AccessorKind::IsGetter: + break; - case AccessorKind::IsMutableAddressor: - D->setAddressorKind(addressorKind); - LLVM_FALLTHROUGH; + case AccessorKind::IsMutableAddressor: + D->setAddressorKind(addressorKind); + LLVM_FALLTHROUGH; - case AccessorKind::IsSetter: - case AccessorKind::IsWillSet: - case AccessorKind::IsDidSet: + case AccessorKind::IsSetter: + case AccessorKind::IsWillSet: + case AccessorKind::IsDidSet: + if (D->isInstanceMember()) D->setMutating(); - break; + break; - case AccessorKind::IsMaterializeForSet: - case AccessorKind::NotAccessor: - llvm_unreachable("not parseable accessors"); - } + case AccessorKind::IsMaterializeForSet: + case AccessorKind::NotAccessor: + llvm_unreachable("not parseable accessors"); } return D; @@ -4682,7 +4726,12 @@ Parser::parseDeclFunc(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, Token NameTok = Tok; SourceLoc NameLoc; - if (Tok.is(tok::identifier) || Tok.isKeyword()) { + if (Tok.isAny(tok::identifier, tok::integer_literal, tok::floating_literal, + tok::unknown) || + Tok.isKeyword()) { + // This non-operator path is quite accepting of what tokens might be a name, + // because we're aggressive about recovering/providing good diagnostics for + // beginners. ParserStatus NameStatus = parseIdentifierDeclName(*this, SimpleName, NameLoc, "function", tok::l_paren, tok::arrow, tok::l_brace, diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 82667b1e30e..13aac5b4895 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -2146,7 +2146,9 @@ static void printTupleNames(const TypeRepr *typeRepr, llvm::raw_ostream &OS) { OS << "("; unsigned elementIndex = 0; - interleave(tupleRepr->getElements(), + llvm::SmallVector elementTypes; + tupleRepr->getElementTypes(elementTypes); + interleave(elementTypes, [&](const TypeRepr *element) { if (isa(element)) { printTupleNames(element, OS); diff --git a/lib/Parse/ParseIfConfig.cpp b/lib/Parse/ParseIfConfig.cpp index 611b5b14f27..2f13a7be579 100644 --- a/lib/Parse/ParseIfConfig.cpp +++ b/lib/Parse/ParseIfConfig.cpp @@ -550,21 +550,20 @@ static bool isVersionIfConfigCondition(Expr *Condition) { } // end anonymous namespace -/// Parse and populate a list of #if/#elseif/#else/#endif clauses. +/// Parse and populate a #if ... #endif directive. /// Delegate callback function to parse elements in the blocks. -template -static ParserStatus parseIfConfig( - Parser &P, SmallVectorImpl> &Clauses, - SourceLoc &EndLoc, bool HadMissingEnd, - llvm::function_ref &, bool)> parseElements) { +ParserResult Parser::parseIfConfig( + llvm::function_ref &, bool)> parseElements) { + + SmallVector Clauses; Parser::StructureMarkerRAII ParsingDecl( - P, P.Tok.getLoc(), Parser::StructureMarkerKind::IfConfig); + *this, Tok.getLoc(), Parser::StructureMarkerKind::IfConfig); bool foundActive = false; bool isVersionCondition = false; while (1) { - bool isElse = P.Tok.is(tok::pound_else); - SourceLoc ClauseLoc = P.consumeToken(); + bool isElse = Tok.is(tok::pound_else); + SourceLoc ClauseLoc = consumeToken(); Expr *Condition = nullptr; bool isActive = false; @@ -572,110 +571,56 @@ static ParserStatus parseIfConfig( if (isElse) { isActive = !foundActive; } else { - llvm::SaveAndRestore S(P.InPoundIfEnvironment, true); - ParserResult Result = P.parseExprSequence(diag::expected_expr, + llvm::SaveAndRestore S(InPoundIfEnvironment, true); + ParserResult Result = parseExprSequence(diag::expected_expr, /*isBasic*/true, /*isForDirective*/true); if (Result.isNull()) return makeParserError(); Condition = Result.get(); - if (validateIfConfigCondition(Condition, P.Context, P.Diags)) { + if (validateIfConfigCondition(Condition, Context, Diags)) { // Error in the condition; isActive = false; isVersionCondition = false; } else if (!foundActive) { // Evaludate the condition only if we haven't found any active one. - isActive = evaluateIfConfigCondition(Condition, P.Context); + isActive = evaluateIfConfigCondition(Condition, Context); isVersionCondition = isVersionIfConfigCondition(Condition); } } foundActive |= isActive; - if (!P.Tok.isAtStartOfLine() && P.Tok.isNot(tok::eof)) { - P.diagnose(P.Tok.getLoc(), - diag::extra_tokens_conditional_compilation_directive); + if (!Tok.isAtStartOfLine() && Tok.isNot(tok::eof)) { + diagnose(Tok.getLoc(), + diag::extra_tokens_conditional_compilation_directive); } // Parse elements - SmallVector Elements; + SmallVector Elements; if (isActive || !isVersionCondition) { parseElements(Elements, isActive); } else { - DiagnosticTransaction DT(P.Diags); - P.skipUntilConditionalBlockClose(); + DiagnosticTransaction DT(Diags); + skipUntilConditionalBlockClose(); DT.abort(); } - Clauses.push_back(IfConfigClause(ClauseLoc, Condition, - P.Context.AllocateCopy(Elements), - isActive)); + Clauses.emplace_back(ClauseLoc, Condition, + Context.AllocateCopy(Elements), isActive); - if (P.Tok.isNot(tok::pound_elseif, tok::pound_else)) + if (Tok.isNot(tok::pound_elseif, tok::pound_else)) break; if (isElse) - P.diagnose(P.Tok, diag::expected_close_after_else_directive); + diagnose(Tok, diag::expected_close_after_else_directive); } - HadMissingEnd = P.parseEndIfDirective(EndLoc); - return makeParserSuccess(); -} - -/// Parse #if ... #endif in declarations position. -ParserResult Parser::parseDeclIfConfig(ParseDeclOptions Flags) { - SmallVector, 4> Clauses; SourceLoc EndLoc; - bool HadMissingEnd = false; - auto Status = parseIfConfig( - *this, Clauses, EndLoc, HadMissingEnd, - [&](SmallVectorImpl &Decls, bool IsActive) { - Optional scope; - if (!IsActive) - scope.emplace(this, getScopeInfo().getCurrentScope()->getKind(), - /*inactiveConfigBlock=*/true); + bool HadMissingEnd = parseEndIfDirective(EndLoc); - ParserStatus Status; - bool PreviousHadSemi = true; - while (Tok.isNot(tok::pound_else, tok::pound_endif, tok::pound_elseif, - tok::eof)) { - if (Tok.is(tok::r_brace)) { - diagnose(Tok.getLoc(), - diag::unexpected_rbrace_in_conditional_compilation_block); - // If we see '}', following declarations don't look like belong to - // the current decl context; skip them. - skipUntilConditionalBlockClose(); - break; - } - Status |= parseDeclItem(PreviousHadSemi, Flags, - [&](Decl *D) {Decls.push_back(D);}); - } - }); - if (Status.isError()) - return makeParserErrorResult(); - - IfConfigDecl *ICD = new (Context) IfConfigDecl(CurDeclContext, - Context.AllocateCopy(Clauses), - EndLoc, HadMissingEnd); + auto *ICD = new (Context) IfConfigDecl(CurDeclContext, + Context.AllocateCopy(Clauses), + EndLoc, HadMissingEnd); return makeParserResult(ICD); } - -/// Parse #if ... #endif in statements position. -ParserResult Parser::parseStmtIfConfig(BraceItemListKind Kind) { - SmallVector, 4> Clauses; - SourceLoc EndLoc; - bool HadMissingEnd = false; - auto Status = parseIfConfig( - *this, Clauses, EndLoc, HadMissingEnd, - [&](SmallVectorImpl &Elements, bool IsActive) { - parseBraceItems(Elements, Kind, IsActive - ? BraceItemListKind::ActiveConditionalBlock - : BraceItemListKind::InactiveConditionalBlock); - }); - if (Status.isError()) - return makeParserErrorResult(); - - auto *ICS = new (Context) IfConfigStmt(Context.AllocateCopy(Clauses), - EndLoc, HadMissingEnd); - return makeParserResult(ICS); -} diff --git a/lib/Parse/ParseSIL.cpp b/lib/Parse/ParseSIL.cpp index ae4bcc69a76..821ee5ebf45 100644 --- a/lib/Parse/ParseSIL.cpp +++ b/lib/Parse/ParseSIL.cpp @@ -2472,6 +2472,7 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB, SILBuilder &B) { if (!P.consumeIf(tok::comma)) break; } + if ((idFn == nullptr && idDecl.isNull() && idProperty == nullptr) || getter == nullptr || (isSettable && setter == nullptr)) { @@ -2509,6 +2510,27 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB, SILBuilder &B) { KeyPathPatternComponent::forComputedGettableProperty( id, getter, {}, componentTy)); } + } else if (componentKind.str() == "optional_wrap" + || componentKind.str() == "optional_chain" + || componentKind.str() == "optional_force") { + CanType ty; + if (P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") + || P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$") + || parseASTType(ty, patternEnv)) + return true; + KeyPathPatternComponent::Kind kind; + + if (componentKind.str() == "optional_wrap") { + kind = KeyPathPatternComponent::Kind::OptionalWrap; + } else if (componentKind.str() == "optional_chain") { + kind = KeyPathPatternComponent::Kind::OptionalChain; + } else if (componentKind.str() == "optional_force") { + kind = KeyPathPatternComponent::Kind::OptionalForce; + } else { + llvm_unreachable("unpossible"); + } + + components.push_back(KeyPathPatternComponent::forOptional(kind, ty)); } else { P.diagnose(componentLoc, diag::sil_keypath_unknown_component_kind, componentKind); diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index cd13134b417..5c3bd0b3491 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -130,14 +130,25 @@ ParserStatus Parser::parseExprOrStmt(ASTNode &Result) { return ResultExpr; } -static bool isTerminatorForBraceItemListKind(const Token &Tok, - BraceItemListKind Kind, - ArrayRef ParsedDecls) { +bool Parser::isTerminatorForBraceItemListKind(BraceItemListKind Kind, + ArrayRef ParsedDecls) { switch (Kind) { case BraceItemListKind::Brace: return false; case BraceItemListKind::Case: - return Tok.is(tok::kw_case) || Tok.is(tok::kw_default); + if (Tok.is(tok::pound_if)) { + // '#if' here could be to guard 'case:' or statements in cases. + // If the next non-directive line starts with 'case' or 'default', it is + // for 'case's. + Parser::BacktrackingScope Backtrack(*this); + do { + consumeToken(); + while (!Tok.isAtStartOfLine() && Tok.isNot(tok::eof)) + skipSingle(); + } while (Tok.isAny(tok::pound_if, tok::pound_elseif, tok::pound_else)); + return Tok.isAny(tok::kw_case, tok::kw_default); + } + return Tok.isAny(tok::kw_case, tok::kw_default); case BraceItemListKind::TopLevelCode: // When parsing the top level executable code for a module, if we parsed // some executable code, then we're done. We want to process (name bind, @@ -247,7 +258,7 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl &Entries, Tok.isNot(tok::kw_sil_witness_table) && Tok.isNot(tok::kw_sil_default_witness_table) && (isConditionalBlock || - !isTerminatorForBraceItemListKind(Tok, Kind, Entries))) { + !isTerminatorForBraceItemListKind(Kind, Entries))) { if (Kind == BraceItemListKind::TopLevelLibrary && skipExtraTopLevelRBraces()) continue; @@ -275,7 +286,8 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl &Entries, // Parse the decl, stmt, or expression. PreviousHadSemi = false; if (isStartOfDecl() - && Tok.isNot(tok::pound_if, tok::pound_sourceLocation)) { + && Tok.isNot( + tok::pound_if, tok::pound_sourceLocation, tok::pound_line)) { ParserResult DeclResult = parseDecl(IsTopLevel ? PD_AllowTopLevel : PD_Default, [&](Decl *D) {TmpDecls.push_back(D);}); @@ -293,11 +305,12 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl &Entries, Entries.push_back(D); TmpDecls.clear(); } else if (Tok.is(tok::pound_if)) { - SourceLoc StartLoc = Tok.getLoc(); - - // We'll want to parse the #if block, but not wrap it in a top-level - // code declaration immediately. - auto IfConfigResult = parseStmtIfConfig(Kind); + auto IfConfigResult = parseIfConfig( + [&](SmallVectorImpl &Elements, bool IsActive) { + parseBraceItems(Elements, Kind, IsActive + ? BraceItemListKind::ActiveConditionalBlock + : BraceItemListKind::InactiveConditionalBlock); + }); if (IfConfigResult.isParseError()) { NeedParseErrorRecovery = true; @@ -311,19 +324,14 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl &Entries, continue; } - // Add the #if block itself as a TLCD if necessary - if (Kind == BraceItemListKind::TopLevelCode) { - auto *TLCD = new (Context) TopLevelCodeDecl(CurDeclContext); - auto Brace = BraceStmt::create(Context, StartLoc, - {Result}, PreviousLoc); - TLCD->setBody(Brace); - Entries.push_back(TLCD); - } else { - Entries.push_back(Result); - } + // Add the #if block itself + Entries.push_back(Result); - IfConfigStmt *ICS = cast(Result.get()); - for (auto &Entry : ICS->getActiveClauseElements()) { + IfConfigDecl *ICD = cast(Result.get()); + for (auto &Entry : ICD->getActiveClauseElements()) { + if (Entry.is() && isa(Entry.get())) + // Don't hoist nested '#if'. + continue; Entries.push_back(Entry); if (Entry.is()) { Entry.get()->setEscapedFromIfConfig(true); @@ -2155,36 +2163,20 @@ ParserResult Parser::parseStmtSwitch(LabeledStmtInfo LabelInfo) { SourceLoc lBraceLoc = consumeToken(tok::l_brace); SourceLoc rBraceLoc; - // If there are non-case-label statements at the start of the switch body, - // raise an error and recover by discarding them. - bool DiagnosedNotCoveredStmt = false; - while (!Tok.is(tok::kw_case) && !Tok.is(tok::kw_default) - && !Tok.is(tok::r_brace) && !Tok.is(tok::eof)) { - if (!DiagnosedNotCoveredStmt) { - diagnose(Tok, diag::stmt_in_switch_not_covered_by_case); - DiagnosedNotCoveredStmt = true; - } - skipSingle(); - } - - SmallVector cases; - bool parsedDefault = false; - bool parsedBlockAfterDefault = false; - while (Tok.is(tok::kw_case) || Tok.is(tok::kw_default)) { - // We cannot have additional cases after a default clause. Complain on - // the first offender. - if (parsedDefault && !parsedBlockAfterDefault) { - parsedBlockAfterDefault = true; - diagnose(Tok, diag::case_after_default); - } + SmallVector cases; + Status |= parseStmtCases(cases, /*IsActive=*/true); - ParserResult Case = parseStmtCase(); - Status |= Case; - if (Case.isNonNull()) { - cases.push_back(Case.get()); - if (Case.get()->isDefault()) - parsedDefault = true; + // We cannot have additional cases after a default clause. Complain on + // the first offender. + bool hasDefault = false; + for (auto Element : cases) { + if (!Element.is()) continue; + auto *CS = cast(Element.get()); + if (hasDefault) { + diagnose(CS->getLoc(), diag::case_after_default); + break; } + hasDefault |= CS->isDefault(); } if (parseMatchingToken(tok::r_brace, rBraceLoc, @@ -2197,6 +2189,51 @@ ParserResult Parser::parseStmtSwitch(LabeledStmtInfo LabelInfo) { lBraceLoc, cases, rBraceLoc, Context)); } +ParserStatus +Parser::parseStmtCases(SmallVectorImpl &cases, bool IsActive) { + ParserStatus Status; + while (Tok.isNot(tok::r_brace, tok::eof, + tok::pound_endif, tok::pound_elseif, tok::pound_else)) { + if (Tok.isAny(tok::kw_case, tok::kw_default)) { + ParserResult Case = parseStmtCase(IsActive); + Status |= Case; + if (Case.isNonNull()) + cases.emplace_back(Case.get()); + } else if (Tok.is(tok::pound_if)) { + // '#if' in 'case' position can enclose one or more 'case' or 'default' + // clauses. + auto IfConfigResult = parseIfConfig( + [&](SmallVectorImpl &Elements, bool IsActive) { + parseStmtCases(Elements, IsActive); + }); + Status |= IfConfigResult; + if (auto ICD = IfConfigResult.getPtrOrNull()) { + cases.emplace_back(ICD); + + for (auto &Entry : ICD->getActiveClauseElements()) { + if (Entry.is() && isa(Entry.get())) + // Don't hoist nested '#if'. + continue; + + assert(Entry.is() && isa(Entry.get())); + cases.push_back(Entry); + } + } + } else { + // If there are non-case-label statements at the start of the switch body, + // raise an error and recover by discarding them. + diagnose(Tok, diag::stmt_in_switch_not_covered_by_case); + + while (Tok.isNot(tok::r_brace, tok::eof, tok::pound_elseif, + tok::pound_else, tok::pound_endif) && + !isTerminatorForBraceItemListKind(BraceItemListKind::Case, {})) { + skipSingle(); + } + } + } + return Status; +} + static ParserStatus parseStmtCase(Parser &P, SourceLoc &CaseLoc, SmallVectorImpl &LabelItems, SmallVectorImpl &BoundDecls, @@ -2261,9 +2298,9 @@ parseStmtCaseDefault(Parser &P, SourceLoc &CaseLoc, return Status; } -ParserResult Parser::parseStmtCase() { +ParserResult Parser::parseStmtCase(bool IsActive) { // A case block has its own scope for variables bound out of the pattern. - Scope S(this, ScopeKind::CaseVars); + Scope S(this, ScopeKind::CaseVars, !IsActive); ParserStatus Status; diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index bec23959988..672b2b25add 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -778,17 +778,13 @@ ParserResult Parser::parseTypeTupleBody() { SourceLoc RPLoc, LPLoc = consumeToken(tok::l_paren); SourceLoc EllipsisLoc; unsigned EllipsisIdx; - SmallVector ElementsR; - - // We keep track of the labels separately, and apply them at the end. - SmallVector, 4> - Labels; + SmallVector ElementsR; ParserStatus Status = parseList(tok::r_paren, LPLoc, RPLoc, /*AllowSepAfterLast=*/false, diag::expected_rparen_tuple_type_list, [&] () -> ParserStatus { - TypeRepr *tyR; + TupleTypeReprElement element; // If this is a deprecated use of the inout marker in an argument list, // consume the inout. @@ -801,23 +797,24 @@ ParserResult Parser::parseTypeTupleBody() { if (Tok.canBeArgumentLabel() && (peekToken().is(tok::colon) || peekToken().canBeArgumentLabel())) { // Consume the name - Identifier name; if (!Tok.is(tok::kw__)) - name = Context.getIdentifier(Tok.getText()); - SourceLoc nameLoc = consumeToken(); + element.Name = Context.getIdentifier(Tok.getText()); + element.NameLoc = consumeToken(); // If there is a second name, consume it as well. - Identifier secondName; - SourceLoc secondNameLoc; if (Tok.canBeArgumentLabel()) { if (!Tok.is(tok::kw__)) - secondName = Context.getIdentifier(Tok.getText()); - secondNameLoc = consumeToken(); + element.SecondName = Context.getIdentifier(Tok.getText()); + element.SecondNameLoc = consumeToken(); } // Consume the ':'. - if (!consumeIf(tok::colon)) + SourceLoc colonLoc; + if (Tok.is(tok::colon)) { + colonLoc = consumeToken(); + } else { diagnose(Tok, diag::expected_parameter_colon); + } SourceLoc postColonLoc = Tok.getLoc(); @@ -827,18 +824,13 @@ ParserResult Parser::parseTypeTupleBody() { return makeParserCodeCompletionStatus(); if (type.isNull()) return makeParserError(); - tyR = type.get(); + element.Type = type.get(); // Complain obsoleted 'inout' position; (inout name: Ty) - if (InOutLoc.isValid() && !isa(tyR)) + if (InOutLoc.isValid() && !isa(element.Type)) diagnose(Tok.getLoc(), diag::inout_as_attr_disallowed) .fixItRemove(InOutLoc) .fixItInsert(postColonLoc, "inout "); - - // Record the label. We will look at these at the end. - if (Labels.empty()) - Labels.resize(ElementsR.size()); - Labels.emplace_back(name, nameLoc, secondName, secondNameLoc); } else { // Otherwise, this has to be a type. auto type = parseType(); @@ -846,24 +838,21 @@ ParserResult Parser::parseTypeTupleBody() { return makeParserCodeCompletionStatus(); if (type.isNull()) return makeParserError(); - tyR = type.get(); - - if (!Labels.empty()) - Labels.emplace_back(); + element.Type = type.get(); } // If an 'inout' marker was specified, build inout type. // Note that we bury the inout locator within the named locator. // This is weird but required by Sema apparently. if (InOutLoc.isValid()) { - if (isa(tyR)) + if (isa(element.Type)) diagnose(Tok, diag::parameter_inout_var_let_repeated) .fixItRemove(InOutLoc); else - tyR = new (Context) InOutTypeRepr(tyR, InOutLoc); + element.Type = new (Context) InOutTypeRepr(element.Type, InOutLoc); } - ElementsR.push_back(tyR); + ElementsR.push_back(element); // Parse '= expr' here so we can complain about it directly, rather // than dying when we see it. @@ -886,6 +875,9 @@ ParserResult Parser::parseTypeTupleBody() { EllipsisIdx = ElementsR.size() - 1; } } + if (Tok.is(tok::comma)) { + element.TrailingCommaLoc = Tok.getLoc(); + } return makeParserSuccess(); }); @@ -896,76 +888,55 @@ ParserResult Parser::parseTypeTupleBody() { if (EllipsisLoc.isInvalid()) EllipsisIdx = ElementsR.size(); - SmallVector ElementNames; - SmallVector ElementNameLocs; - SmallVector UnderscoreLocs; // If there were any labels, figure out which labels should go into the type // representation. - if (!Labels.empty()) { - assert(Labels.size() == ElementsR.size()); - bool isFunctionType = Tok.isAny(tok::arrow, tok::kw_throws, - tok::kw_rethrows); - ElementNames.resize(ElementsR.size()); - ElementNameLocs.resize(ElementsR.size()); - if (isFunctionType) - UnderscoreLocs.resize(ElementsR.size()); + bool isFunctionType = Tok.isAny(tok::arrow, tok::kw_throws, + tok::kw_rethrows); - for (unsigned i : indices(ElementsR)) { - auto ¤tLabel = Labels[i]; - - Identifier firstName = std::get<0>(currentLabel); - SourceLoc firstNameLoc = std::get<1>(currentLabel); - Identifier secondName = std::get<2>(currentLabel); - SourceLoc secondNameLoc = std::get<3>(currentLabel); - - // True tuples have labels. - if (!isFunctionType) { - // If there were two names, complain. - if (firstNameLoc.isValid() && secondNameLoc.isValid()) { - auto diag = diagnose(firstNameLoc, diag::tuple_type_multiple_labels); - if (firstName.empty()) { - diag.fixItRemoveChars(firstNameLoc, ElementsR[i]->getStartLoc()); - } else { - diag.fixItRemove( - SourceRange(Lexer::getLocForEndOfToken(SourceMgr,firstNameLoc), - secondNameLoc)); - } + for (auto &element : ElementsR) { + // True tuples have labels. + if (!isFunctionType) { + // If there were two names, complain. + if (element.NameLoc.isValid() && element.SecondNameLoc.isValid()) { + auto diag = diagnose(element.NameLoc, diag::tuple_type_multiple_labels); + if (element.Name.empty()) { + diag.fixItRemoveChars(element.NameLoc, + element.Type->getStartLoc()); + } else { + diag.fixItRemove( + SourceRange(Lexer::getLocForEndOfToken(SourceMgr, element.NameLoc), + element.SecondNameLoc)); } - - // Form the named type representation. - ElementNames[i] = firstName; - ElementNameLocs[i] = firstNameLoc; - continue; } + continue; + } - // If there was a first name, complain; arguments in function types are - // always unlabeled. - if (firstNameLoc.isValid() && !firstName.empty()) { - auto diag = diagnose(firstNameLoc, diag::function_type_argument_label, - firstName); - if (secondNameLoc.isInvalid()) - diag.fixItInsert(firstNameLoc, "_ "); - else if (secondName.empty()) - diag.fixItRemoveChars(firstNameLoc, ElementsR[i]->getStartLoc()); - else - diag.fixItReplace(SourceRange(firstNameLoc), "_"); - } + // If there was a first name, complain; arguments in function types are + // always unlabeled. + if (element.NameLoc.isValid() && !element.Name.empty()) { + auto diag = diagnose(element.NameLoc, diag::function_type_argument_label, + element.Name); + if (element.SecondNameLoc.isInvalid()) + diag.fixItInsert(element.NameLoc, "_ "); + else if (element.SecondName.empty()) + diag.fixItRemoveChars(element.NameLoc, + element.Type->getStartLoc()); + else + diag.fixItReplace(SourceRange(element.NameLoc), "_"); + } - if (firstNameLoc.isValid() || secondNameLoc.isValid()) { - // Form the named parameter type representation. - ElementNames[i] = secondName; - ElementNameLocs[i] = secondNameLoc; - UnderscoreLocs[i] = firstNameLoc; - } + if (element.NameLoc.isValid() || element.SecondNameLoc.isValid()) { + // Form the named parameter type representation. + element.Name = element.SecondName; + element.NameLoc = element.SecondNameLoc; + element.UnderscoreLoc = element.NameLoc; } } return makeParserResult(Status, TupleTypeRepr::create(Context, ElementsR, SourceRange(LPLoc, RPLoc), - ElementNames, ElementNameLocs, - UnderscoreLocs, EllipsisLoc, EllipsisIdx)); } diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 8dc7948a1a3..76c1cf3307b 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -282,7 +282,7 @@ std::vector swift::tokenize(const LangOptions &LangOpts, } // TODO: Refactor into common implementation with swift::tokenize. -std::vector, +std::vector, syntax::AbsolutePosition>> swift::tokenizeWithTrivia(const LangOptions &LangOpts, const SourceManager &SM, @@ -296,7 +296,7 @@ swift::tokenizeWithTrivia(const LangOptions &LangOpts, CommentRetentionMode::AttachToNextToken, TriviaRetentionMode::WithTrivia, Offset, EndOffset); - std::vector, + std::vector, syntax::AbsolutePosition>> Tokens; syntax::AbsolutePosition RunningPos; do { @@ -770,7 +770,7 @@ void Parser::diagnoseRedefinition(ValueDecl *Prev, ValueDecl *New) { assert(New != Prev && "Cannot conflict with self"); diagnose(New->getLoc(), diag::decl_redefinition, New->isDefinition()); diagnose(Prev->getLoc(), diag::previous_decldef, Prev->isDefinition(), - Prev->getName()); + Prev->getBaseName()); } struct ParserUnit::Implementation { diff --git a/lib/PrintAsObjC/PrintAsObjC.cpp b/lib/PrintAsObjC/PrintAsObjC.cpp index b29b2fb8658..096c24db5cd 100644 --- a/lib/PrintAsObjC/PrintAsObjC.cpp +++ b/lib/PrintAsObjC/PrintAsObjC.cpp @@ -2605,9 +2605,8 @@ public: assert(*lhs != *rhs && "duplicate top-level decl"); auto getSortName = [](const Decl *D) -> StringRef { - // TODO: Handle special names if (auto VD = dyn_cast(D)) - return VD->getBaseName().getIdentifier().str(); + return VD->getBaseName().userFacingName(); if (auto ED = dyn_cast(D)) { auto baseClass = ED->getExtendedType()->getClassOrBoundGenericClass(); diff --git a/lib/SIL/DynamicCasts.cpp b/lib/SIL/DynamicCasts.cpp index 2bf41523c43..e956100da65 100644 --- a/lib/SIL/DynamicCasts.cpp +++ b/lib/SIL/DynamicCasts.cpp @@ -390,6 +390,22 @@ swift::classifyDynamicCast(ModuleDecl *M, sourceMetatype.isAnyExistentialType()) return DynamicCastFeasibility::WillSucceed; + // If the source and target are the same existential type, but the source is + // P.Protocol and the dest is P.Type, then we need to consider whether the + // protocol is self-conforming. + // The only cases where a protocol self-conforms are objc protocols, but + // we're going to expect P.Type to hold a class object. And this case + // doesn't matter since for a self-conforming protocol type there can't be + // any type-level methods. + // Thus we consider this kind of cast to always fail. The only exception + // from this rule is when the target is Any.Type, because *.Protocol + // can always be casted to Any.Type. + if (source->isAnyExistentialType() && isa(sourceMetatype) && + isa(targetMetatype)) { + return target->isAny() ? DynamicCastFeasibility::WillSucceed + : DynamicCastFeasibility::WillFail; + } + if (targetMetatype.isAnyExistentialType() && (isa(target) || isa(target))) { auto Feasibility = classifyDynamicCastToProtocol(source, diff --git a/lib/SIL/SILDeclRef.cpp b/lib/SIL/SILDeclRef.cpp index b5d81b149fb..8cbfb9fae98 100644 --- a/lib/SIL/SILDeclRef.cpp +++ b/lib/SIL/SILDeclRef.cpp @@ -430,6 +430,33 @@ SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const { if (isClangImported()) return SILLinkage::Shared; + // Stored property initializers get the linkage of their containing type. + if (isStoredPropertyInitializer()) { + // If the property is public, the initializer needs to be public, because + // it might be referenced from an inlineable initializer. + // + // Note that we don't serialize the presence of an initializer, so there's + // no way to reference one from another module except for this case. + // + // This is silly, and we need a proper resilience story here. + if (d->getEffectiveAccess() == Accessibility::Public) + return maybeAddExternal(SILLinkage::Public); + + d = cast(d->getDeclContext()); + + // Otherwise, use the visibility of the type itself, because even if the + // property is private, we might reference the initializer from another + // file. + switch (d->getEffectiveAccess()) { + case Accessibility::Private: + case Accessibility::FilePrivate: + return maybeAddExternal(SILLinkage::Private); + + default: + return maybeAddExternal(SILLinkage::Hidden); + } + } + // Otherwise, we have external linkage. switch (d->getEffectiveAccess()) { case Accessibility::Private: diff --git a/lib/SIL/SILFunctionType.cpp b/lib/SIL/SILFunctionType.cpp index 82814e26da6..e0bd6f937f4 100644 --- a/lib/SIL/SILFunctionType.cpp +++ b/lib/SIL/SILFunctionType.cpp @@ -383,9 +383,10 @@ enum class ConventionsKind : uint8_t { SmallVectorImpl &inputs) : M(M), Convs(conventions), ForeignError(foreignError), Inputs(inputs) {} - void destructure(AbstractionPattern origType, CanType substType, + void destructure(AbstractionPattern origType, + ArrayRef params, AnyFunctionType::ExtInfo extInfo) { - visitTopLevelType(origType, substType, extInfo); + visitTopLevelParams(origType, params, extInfo); maybeAddForeignErrorParameter(); } @@ -424,22 +425,12 @@ enum class ConventionsKind : uint8_t { ClassDecl::ForeignKind::CFType) { return false; } - // swift_newtype-ed CF type as foreign class - if (auto typedefTy = clangTy->getAs()) { - if (typedefTy->getDecl()->getAttr()) { - // Make sure that we actually made the struct during import - if (auto underlyingType = - substTy->getSwiftNewtypeUnderlyingType()) { - if (auto underlyingClass = - underlyingType->getClassOrBoundGenericClass()) { - if (underlyingClass->getForeignClassKind() == - ClassDecl::ForeignKind::CFType) { - return false; - } - } - } - } - } + } + + // swift_newtypes are always passed directly + if (auto typedefTy = clangTy->getAs()) { + if (typedefTy->getDecl()->getAttr()) + return false; } return true; @@ -513,33 +504,35 @@ enum class ConventionsKind : uint8_t { /// This is a special entry point that allows destructure inputs to handle /// self correctly. - void visitTopLevelType(AbstractionPattern origType, CanType substType, - AnyFunctionType::ExtInfo extInfo) { + void visitTopLevelParams(AbstractionPattern origType, + ArrayRef params, + AnyFunctionType::ExtInfo extInfo) { // If we don't have 'self', we don't need to do anything special. if (!extInfo.hasSelfParam()) { - return visit(origType, substType); + if (params.empty()) { + return visit(origType, M.getASTContext().TheEmptyTupleType); + } else { + CanType ty = AnyFunctionType::composeInput(M.getASTContext(), params, + /*canonicalVararg*/true) + ->getCanonicalType(); + return visit(origType, ty); + } } // Okay, handle 'self'. - if (auto substTupleType = dyn_cast(substType)) { - unsigned numEltTypes = substTupleType.getElementTypes().size(); - assert(numEltTypes > 0); + unsigned numEltTypes = params.size(); + assert(numEltTypes > 0); - // Process all the non-self parameters. - unsigned numNonSelfParams = numEltTypes - 1; - for (unsigned i = 0; i != numNonSelfParams; ++i) { - visit(origType.getTupleElementType(i), - substTupleType.getElementType(i)); - } - - // Process the self parameter. - visitSelfType(origType.getTupleElementType(numNonSelfParams), - substTupleType.getElementType(numNonSelfParams), - extInfo.getSILRepresentation()); - } else { - visitSelfType(origType, substType, - extInfo.getSILRepresentation()); + // Process all the non-self parameters. + unsigned numNonSelfParams = numEltTypes - 1; + for (unsigned i = 0; i != numNonSelfParams; ++i) { + visit(origType.getTupleElementType(i), params[i].getCanType()); } + + // Process the self parameter. + visitSelfType(origType.getTupleElementType(numNonSelfParams), + params[numNonSelfParams].getCanType(), + extInfo.getSILRepresentation()); } void visit(AbstractionPattern origType, CanType substType) { @@ -549,14 +542,12 @@ enum class ConventionsKind : uint8_t { // we should not expand it. CanTupleType substTupleTy = dyn_cast(substType); if (substTupleTy && - (!origType.isTypeParameter() || - substTupleTy->hasInOutElement())) { - auto substTuple = cast(substType); + (!origType.isTypeParameter() || substTupleTy->hasInOutElement())) { assert(origType.isTypeParameter() || - origType.getNumTupleElements() == substTuple->getNumElements()); - for (auto i : indices(substTuple.getElementTypes())) { + origType.getNumTupleElements() == substTupleTy->getNumElements()); + for (auto i : indices(substTupleTy.getElementTypes())) { visit(origType.getTupleElementType(i), - substTuple.getElementType(i)); + substTupleTy.getElementType(i)); } return; } @@ -749,7 +740,7 @@ static CanSILFunctionType getSILFunctionType(SILModule &M, { DestructureInputs destructurer(M, conventions, foreignError, inputs); destructurer.destructure(origType.getFunctionInputType(), - substFnInterfaceType.getInput(), + substFnInterfaceType.getParams(), extInfo); } @@ -2318,7 +2309,7 @@ TypeConverter::getLoweredASTFunctionType(CanAnyFunctionType fnType, // Merge inputs and generic parameters from the uncurry levels. for (;;) { - inputs.push_back(TupleTypeElt(fnType->getInput())); + inputs.push_back(TupleTypeElt(fnType->getInput()->getCanonicalType())); // The uncurried function calls all of the intermediate function // levels and so throws if any of them do. diff --git a/lib/SIL/SILInstructions.cpp b/lib/SIL/SILInstructions.cpp index 20e2f4b62db..4e435b53b24 100644 --- a/lib/SIL/SILInstructions.cpp +++ b/lib/SIL/SILInstructions.cpp @@ -1984,6 +1984,9 @@ bool KeyPathPatternComponent::isComputedSettablePropertyMutating() const { switch (getKind()) { case Kind::StoredProperty: case Kind::GettableProperty: + case Kind::OptionalChain: + case Kind::OptionalWrap: + case Kind::OptionalForce: llvm_unreachable("not a settable computed property"); case Kind::SettableProperty: { auto setter = getComputedPropertySetter(); @@ -1998,6 +2001,9 @@ forEachRefcountableReference(const KeyPathPatternComponent &component, llvm::function_ref forFunction) { switch (component.getKind()) { case KeyPathPatternComponent::Kind::StoredProperty: + case KeyPathPatternComponent::Kind::OptionalChain: + case KeyPathPatternComponent::Kind::OptionalWrap: + case KeyPathPatternComponent::Kind::OptionalForce: return; case KeyPathPatternComponent::Kind::SettableProperty: forFunction(component.getComputedPropertySetter()); @@ -2044,6 +2050,9 @@ KeyPathPattern::get(SILModule &M, CanGenericSignature signature, for (auto component : components) { switch (component.getKind()) { case KeyPathPatternComponent::Kind::StoredProperty: + case KeyPathPatternComponent::Kind::OptionalChain: + case KeyPathPatternComponent::Kind::OptionalWrap: + case KeyPathPatternComponent::Kind::OptionalForce: break; case KeyPathPatternComponent::Kind::GettableProperty: @@ -2105,6 +2114,11 @@ void KeyPathPattern::Profile(llvm::FoldingSetNodeID &ID, for (auto &component : components) { ID.AddInteger((unsigned)component.getKind()); switch (component.getKind()) { + case KeyPathPatternComponent::Kind::OptionalForce: + case KeyPathPatternComponent::Kind::OptionalWrap: + case KeyPathPatternComponent::Kind::OptionalChain: + break; + case KeyPathPatternComponent::Kind::StoredProperty: ID.AddPointer(component.getStoredPropertyDecl()); break; diff --git a/lib/SIL/SILModule.cpp b/lib/SIL/SILModule.cpp index a9609774980..477ef5b0a43 100644 --- a/lib/SIL/SILModule.cpp +++ b/lib/SIL/SILModule.cpp @@ -83,12 +83,10 @@ class SILModule::SerializationCallback : public SerializedSILLoader::Callback { }; SILModule::SILModule(ModuleDecl *SwiftModule, SILOptions &Options, - const DeclContext *associatedDC, bool wholeModule, - bool wholeModuleSerialized) + const DeclContext *associatedDC, bool wholeModule) : TheSwiftModule(SwiftModule), AssociatedDeclContext(associatedDC), Stage(SILStage::Raw), Callback(new SILModule::SerializationCallback()), - wholeModule(wholeModule), WholeModuleSerialized(wholeModuleSerialized), - Options(Options), Types(*this) {} + wholeModule(wholeModule), Options(Options), Types(*this) {} SILModule::~SILModule() { // Decrement ref count for each SILGlobalVariable with static initializers. diff --git a/lib/SIL/SILPrinter.cpp b/lib/SIL/SILPrinter.cpp index 1fd89cba79e..2bf4c2be8e8 100644 --- a/lib/SIL/SILPrinter.cpp +++ b/lib/SIL/SILPrinter.cpp @@ -1860,6 +1860,25 @@ public: && "todo"); break; } + case KeyPathPatternComponent::Kind::OptionalWrap: + case KeyPathPatternComponent::Kind::OptionalChain: + case KeyPathPatternComponent::Kind::OptionalForce: { + switch (kind) { + case KeyPathPatternComponent::Kind::OptionalWrap: + *this << "optional_wrap : $"; + break; + case KeyPathPatternComponent::Kind::OptionalChain: + *this << "optional_chain : $"; + break; + case KeyPathPatternComponent::Kind::OptionalForce: + *this << "optional_force : $"; + break; + default: + llvm_unreachable("out of sync"); + } + *this << component.getComponentType(); + break; + } } } diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp index 4556a3d3acf..68dbc49c453 100644 --- a/lib/SIL/SILVerifier.cpp +++ b/lib/SIL/SILVerifier.cpp @@ -3817,6 +3817,24 @@ public: break; } + case KeyPathPatternComponent::Kind::OptionalChain: { + require(OptionalType::get(componentTy)->isEqual(baseTy), + "chaining component should unwrap optional"); + require(leafTy->getAnyOptionalObjectType(), + "key path with chaining component should have optional " + "result"); + break; + } + case KeyPathPatternComponent::Kind::OptionalForce: { + require(OptionalType::get(componentTy)->isEqual(baseTy), + "forcing component should unwrap optional"); + break; + } + case KeyPathPatternComponent::Kind::OptionalWrap: { + require(OptionalType::get(baseTy)->isEqual(componentTy), + "wrapping component should wrap optional"); + break; + } } baseTy = componentTy; diff --git a/lib/SIL/SILWitnessTable.cpp b/lib/SIL/SILWitnessTable.cpp index 765bf792ec8..8afb771e388 100644 --- a/lib/SIL/SILWitnessTable.cpp +++ b/lib/SIL/SILWitnessTable.cpp @@ -21,6 +21,7 @@ #include "swift/SIL/SILWitnessTable.h" #include "swift/AST/ASTMangler.h" +#include "swift/AST/Module.h" #include "swift/AST/ProtocolConformance.h" #include "swift/SIL/SILModule.h" #include "llvm/ADT/SmallString.h" @@ -155,3 +156,18 @@ void SILWitnessTable::convertToDefinition(ArrayRef entries, Identifier SILWitnessTable::getIdentifier() const { return Mod.getASTContext().getIdentifier(Name); } + +bool SILWitnessTable::conformanceIsSerialized(ProtocolConformance *conformance, + ResilienceStrategy strategy, + bool silSerializeWitnessTables) { + auto *nominal = conformance->getType()->getAnyNominal(); + // Only serialize if the witness table is sufficiently static, and resilience + // is explicitly enabled for this compilation or if we serialize all eligible + // witness tables. + auto moduleIsResilient = strategy == ResilienceStrategy::Resilient; + auto protocolIsPublic = + conformance->getProtocol()->getEffectiveAccess() >= Accessibility::Public; + auto typeIsPublic = nominal->getEffectiveAccess() >= Accessibility::Public; + return (moduleIsResilient || silSerializeWitnessTables) && + nominal->hasFixedLayout() && protocolIsPublic && typeIsPublic; +} diff --git a/lib/SIL/TypeLowering.cpp b/lib/SIL/TypeLowering.cpp index 759b52a3da2..93e97b799b9 100644 --- a/lib/SIL/TypeLowering.cpp +++ b/lib/SIL/TypeLowering.cpp @@ -1891,12 +1891,11 @@ TypeConverter::getFunctionInterfaceTypeWithCaptures(CanAnyFunctionType funcType, funcType->throws()); if (!genericSig) - return CanFunctionType::get(funcType.getInput(), - funcType.getResult(), + return CanFunctionType::get(funcType->getParams(), funcType.getResult(), innerExtInfo); - + return CanGenericFunctionType::get(genericSig, - funcType.getInput(), + funcType->getParams(), funcType.getResult(), innerExtInfo); } diff --git a/lib/SIL/ValueOwnershipKindClassifier.cpp b/lib/SIL/ValueOwnershipKindClassifier.cpp index d1ba5ce7b2c..e8187876fe0 100644 --- a/lib/SIL/ValueOwnershipKindClassifier.cpp +++ b/lib/SIL/ValueOwnershipKindClassifier.cpp @@ -62,6 +62,7 @@ CONSTANT_OWNERSHIP_INST(Trivial, AddressToPointer) CONSTANT_OWNERSHIP_INST(Trivial, AllocStack) CONSTANT_OWNERSHIP_INST(Trivial, BindMemory) CONSTANT_OWNERSHIP_INST(Trivial, BeginAccess) +CONSTANT_OWNERSHIP_INST(Trivial, BeginUnpairedAccess) CONSTANT_OWNERSHIP_INST(Trivial, BridgeObjectToWord) CONSTANT_OWNERSHIP_INST(Trivial, ClassMethod) CONSTANT_OWNERSHIP_INST(Trivial, DynamicMethod) @@ -144,7 +145,6 @@ CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Guaranteed, TupleExtract) assert(!I->hasValue() && "Expected an instruction without a result"); \ llvm_unreachable("Instruction without a result can not have ownership"); \ } -NO_RESULT_OWNERSHIP_INST(BeginUnpairedAccess) NO_RESULT_OWNERSHIP_INST(DeallocStack) NO_RESULT_OWNERSHIP_INST(DeallocRef) NO_RESULT_OWNERSHIP_INST(DeallocPartialRef) diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index 5a5ea2a2d4c..82f2e43c154 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -38,9 +38,9 @@ using namespace Lowering; // SILGenModule Class implementation //===----------------------------------------------------------------------===// -SILGenModule::SILGenModule(SILModule &M, ModuleDecl *SM, bool makeModuleFragile) +SILGenModule::SILGenModule(SILModule &M, ModuleDecl *SM) : M(M), Types(M.Types), SwiftModule(SM), TopLevelSGF(nullptr), - Profiler(nullptr), makeModuleFragile(makeModuleFragile) { + Profiler(nullptr) { } SILGenModule::~SILGenModule() { @@ -451,7 +451,7 @@ SILFunction *SILGenModule::getEmittedFunction(SILDeclRef constant, if (isAvailableExternally(F->getLinkage())) { F->setLinkage(constant.getLinkage(ForDefinition)); } - if (makeModuleFragile) { + if (isMakeModuleFragile()) { F->setSerialized(IsSerialized); } } @@ -498,7 +498,7 @@ SILFunction *SILGenModule::getFunction(SILDeclRef constant, assert(F && "SILFunction should have been defined"); - if (makeModuleFragile) { + if (isMakeModuleFragile()) { SILLinkage linkage = constant.getLinkage(forDefinition); if (linkage != SILLinkage::PublicExternal) { F->setSerialized(IsSerialized); @@ -977,7 +977,7 @@ SILFunction *SILGenModule::emitLazyGlobalInitializer(StringRef funcName, M.createFunction(SILLinkage::Private, funcName, initSILType, nullptr, SILLocation(binding), IsNotBare, IsNotTransparent, - makeModuleFragile + isMakeModuleFragile() ? IsSerialized : IsNotSerialized); f->setDebugScope(new (M) SILDebugScope(RegularLocation(binding), f)); @@ -1393,7 +1393,7 @@ void SILGenModule::emitSourceFile(SourceFile *sf, unsigned startElem) { std::unique_ptr SILModule::constructSIL(ModuleDecl *mod, SILOptions &options, FileUnit *SF, - Optional startElem, bool makeModuleFragile, + Optional startElem, bool isWholeModule) { SharedTimer timer("SILGen"); const DeclContext *DC; @@ -1409,8 +1409,8 @@ SILModule::constructSIL(ModuleDecl *mod, SILOptions &options, FileUnit *SF, } std::unique_ptr M( - new SILModule(mod, options, DC, isWholeModule, makeModuleFragile)); - SILGenModule SGM(*M, mod, makeModuleFragile); + new SILModule(mod, options, DC, isWholeModule)); + SILGenModule SGM(*M, mod); if (SF) { if (auto *file = dyn_cast(SF)) { @@ -1468,16 +1468,14 @@ SILModule::constructSIL(ModuleDecl *mod, SILOptions &options, FileUnit *SF, std::unique_ptr swift::performSILGeneration(ModuleDecl *mod, SILOptions &options, - bool makeModuleFragile, bool wholeModuleCompilation) { - return SILModule::constructSIL(mod, options, nullptr, None, makeModuleFragile, + return SILModule::constructSIL(mod, options, nullptr, None, wholeModuleCompilation); } std::unique_ptr swift::performSILGeneration(FileUnit &sf, SILOptions &options, - Optional startElem, - bool makeModuleFragile) { + Optional startElem) { return SILModule::constructSIL(sf.getParentModule(), options, &sf, startElem, - makeModuleFragile, false); + false); } diff --git a/lib/SILGen/SILGen.h b/lib/SILGen/SILGen.h index b7d6d4ed6d1..6f1cfa61355 100644 --- a/lib/SILGen/SILGen.h +++ b/lib/SILGen/SILGen.h @@ -106,7 +106,7 @@ public: /// If true, all functions and globals are made fragile. Currently only used /// for compiling the stdlib. - bool makeModuleFragile; + bool isMakeModuleFragile() const { return M.getOptions().SILSerializeAll; } Optional StringToNSStringFn; Optional NSStringToStringFn; @@ -136,7 +136,7 @@ public: Optional NSErrorConformanceToError; public: - SILGenModule(SILModule &M, ModuleDecl *SM, bool makeModuleFragile); + SILGenModule(SILModule &M, ModuleDecl *SM); ~SILGenModule(); diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index c05858e747b..8da0b68a703 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -632,6 +632,7 @@ public: SelfApplyExpr = theSelfApplyExpr; SelfType = theSelfApplyExpr->getType(); } + void setSelfParam(ArgumentSource &&theSelfParam, Type selfType) { assert(!SelfParam && "already set this!"); SelfParam = std::move(theSelfParam); @@ -661,12 +662,41 @@ public: void visitApplyExpr(ApplyExpr *e) { if (e->isSuper()) { applySuper(e); - } else if (applyInitDelegation(e)) { - // Already done - } else { - CallSites.push_back(e); - visit(e->getFn()); + return; } + + if (applyInitDelegation(e)) + return; + + CallSites.push_back(e); + visit(e->getFn()); + } + + /// Idempotently convert a metatype to an objc metatype. + std::pair convertToObjCMetatype(ManagedValue selfMeta, + SILLocation loc) { + auto metaType = selfMeta.getType().castTo(); + CanType instanceType = metaType.getInstanceType(); + + // If we are already objc, just return. + if (metaType->getRepresentation() == MetatypeRepresentation::ObjC) { + return {selfMeta, SGF.SGM.getLoweredType(instanceType)}; + } + + CanAnyMetatypeType objcMetaType; + if (isa(metaType)) { + objcMetaType = + CanMetatypeType::get(instanceType, MetatypeRepresentation::ObjC); + } else { + objcMetaType = CanExistentialMetatypeType::get( + instanceType, MetatypeRepresentation::ObjC); + } + // ObjC metatypes are trivial and thus do not have a cleanup. Only if we + // convert them to an object do they become non-trivial. + assert(!selfMeta.hasCleanup()); + auto result = ManagedValue::forUnmanaged(SGF.B.emitThickToObjCMetatype( + loc, selfMeta.getValue(), SGF.SGM.getLoweredType(objcMetaType))); + return {result, SGF.SGM.getLoweredType(instanceType)}; } /// Given a metatype value for the type, allocate an Objective-C @@ -674,35 +704,167 @@ public: /// /// \returns the self object. ManagedValue allocateObjCObject(ManagedValue selfMeta, SILLocation loc) { - auto metaType = selfMeta.getType().castTo(); - CanType type = metaType.getInstanceType(); - // Convert to an Objective-C metatype representation, if needed. ManagedValue selfMetaObjC; - if (metaType->getRepresentation() == MetatypeRepresentation::ObjC) { - selfMetaObjC = selfMeta; - } else { - CanAnyMetatypeType objcMetaType; - if (isa(metaType)) { - objcMetaType = CanMetatypeType::get(type, MetatypeRepresentation::ObjC); - } else { - objcMetaType = CanExistentialMetatypeType::get(type, - MetatypeRepresentation::ObjC); - } - // ObjC metatypes are trivial and thus do not have a cleanup. Only if we - // convert them to an object do they become non-trivial. - assert(!selfMeta.hasCleanup()); - selfMetaObjC = ManagedValue::forUnmanaged(SGF.B.emitThickToObjCMetatype( - loc, selfMeta.getValue(), SGF.SGM.getLoweredType(objcMetaType))); - } + SILType instanceType; + std::tie(selfMetaObjC, instanceType) = convertToObjCMetatype(selfMeta, loc); // Allocate the object. - return ManagedValue(SGF.B.createAllocRefDynamic( - loc, - selfMetaObjC.getValue(), - SGF.SGM.getLoweredType(type), - /*objc=*/true, {}, {}), - selfMetaObjC.getCleanup()); + return ManagedValue( + SGF.B.createAllocRefDynamic(loc, selfMetaObjC.getValue(), instanceType, + /*objc=*/true, {}, {}), + selfMetaObjC.getCleanup()); + } + + void processProtocolDecl(DeclRefExpr *e, AbstractFunctionDecl *afd, + ProtocolDecl *proto) { + assert(!CallSites.empty()); + ApplyExpr *thisCallSite = CallSites.back(); + CallSites.pop_back(); + + ArgumentSource selfValue = thisCallSite->getArg(); + + SubstitutionList subs = e->getDeclRef().getSubstitutions(); + + SILDeclRef::Kind kind = SILDeclRef::Kind::Func; + if (isa(afd)) { + if (proto->isObjC()) { + SILLocation loc = thisCallSite->getArg(); + + // For Objective-C initializers, we only have an initializing + // initializer. We need to allocate the object ourselves. + kind = SILDeclRef::Kind::Initializer; + + auto metatype = std::move(selfValue).getAsSingleValue(SGF); + auto allocated = allocateObjCObject(metatype, loc); + auto allocatedType = allocated.getType().getSwiftRValueType(); + selfValue = + ArgumentSource(loc, RValue(SGF, loc, allocatedType, allocated)); + } else { + // For non-Objective-C initializers, we have an allocating + // initializer to call. + kind = SILDeclRef::Kind::Allocator; + } + } + + SILDeclRef constant = SILDeclRef(afd, kind); + + // Prepare the callee. This can modify both selfValue and subs. + Callee theCallee = Callee::forArchetype(SGF, selfValue.getSubstRValueType(), + constant, subs, e); + AssumedPlusZeroSelf = + selfValue.isRValue() && + selfValue.forceAndPeekRValue(SGF).peekIsPlusZeroRValueOrTrivial(); + + setSelfParam(std::move(selfValue), thisCallSite); + setCallee(std::move(theCallee)); + } + + bool processAbstractFunctionDecl(DeclRefExpr *e, AbstractFunctionDecl *afd) { + // We have four cases to deal with here: + // + // 1) for a "static" / "type" method, the base is a metatype. + // 2) for a classbound protocol, the base is a class-bound protocol + // rvalue, + // which is loadable. + // 3) for a mutating method, the base has inout type. + // 4) for a nonmutating method, the base is a general archetype + // rvalue, which is address-only. The base is passed at +0, so it + // isn't + // consumed. + // + // In the last case, the AST has this call typed as being applied + // to an rvalue, but the witness is actually expecting a pointer + // to the +0 value in memory. We just pass in the address since + // archetypes are address-only. + + if (auto *proto = dyn_cast(afd->getDeclContext())) { + processProtocolDecl(e, afd, proto); + return true; + } + + Optional kind; + bool isDynamicallyDispatched; + bool requiresAllocRefDynamic = false; + + // Determine whether the method is dynamically dispatched. + if (e->getAccessSemantics() != AccessSemantics::Ordinary) { + isDynamicallyDispatched = false; + } else { + switch (getMethodDispatch(afd)) { + case MethodDispatch::Class: + isDynamicallyDispatched = true; + break; + case MethodDispatch::Static: + isDynamicallyDispatched = false; + break; + } + } + + if (isa(afd) && isDynamicallyDispatched) { + kind = SILDeclRef::Kind::Func; + } else if (auto ctor = dyn_cast(afd)) { + ApplyExpr *thisCallSite = CallSites.back(); + // Required constructors are dynamically dispatched when the 'self' + // value is not statically derived. + if (ctor->isRequired() && + thisCallSite->getArg()->getType()->is() && + !thisCallSite->getArg()->isStaticallyDerivedMetatype()) { + if (requiresForeignEntryPoint(afd)) { + // When we're performing Objective-C dispatch, we don't have an + // allocating constructor to call. So, perform an alloc_ref_dynamic + // and pass that along to the initializer. + requiresAllocRefDynamic = true; + kind = SILDeclRef::Kind::Initializer; + } else { + kind = SILDeclRef::Kind::Allocator; + } + } else { + isDynamicallyDispatched = false; + } + } + + if (!isDynamicallyDispatched) + return false; + + // At this point, we know for sure that we are actually dynamically + // dispatched. + ApplyExpr *thisCallSite = CallSites.back(); + CallSites.pop_back(); + + // Emit the rvalue for self, allowing for guaranteed plus zero if we + // have a func. + bool AllowPlusZero = kind && *kind == SILDeclRef::Kind::Func; + RValue self = SGF.emitRValue( + thisCallSite->getArg(), + AllowPlusZero ? SGFContext::AllowGuaranteedPlusZero : SGFContext()); + + // If we allowed for PlusZero and we *did* get the value back at +0, + // then we assumed that self could be passed at +0. We will check later + // if the actual callee passes self at +1 later when we know its actual + // type. + AssumedPlusZeroSelf = + AllowPlusZero && self.peekIsPlusZeroRValueOrTrivial(); + + // If we require a dynamic allocation of the object here, do so now. + if (requiresAllocRefDynamic) { + SILLocation loc = thisCallSite->getArg(); + auto selfValue = + allocateObjCObject(std::move(self).getAsSingleValue(SGF, loc), loc); + self = RValue(SGF, loc, selfValue.getType().getSwiftRValueType(), + selfValue); + } + + auto selfValue = self.peekScalarValue(); + + setSelfParam(ArgumentSource(thisCallSite->getArg(), std::move(self)), + thisCallSite); + auto constant = SILDeclRef(afd, kind.getValue()) + .asForeign(requiresForeignEntryPoint(afd)); + + auto subs = e->getDeclRef().getSubstitutions(); + setCallee(Callee::forClassMethod(SGF, selfValue, constant, subs, e)); + return true; } // @@ -711,146 +873,10 @@ public: void visitDeclRefExpr(DeclRefExpr *e) { // If we need to perform dynamic dispatch for the given function, // emit class_method to do so. - if (auto afd = dyn_cast(e->getDecl())) { - Optional kind; - bool isDynamicallyDispatched; - bool requiresAllocRefDynamic = false; - - // Determine whether the method is dynamically dispatched. - if (auto *proto = dyn_cast(afd->getDeclContext())) { - // We have four cases to deal with here: - // - // 1) for a "static" / "type" method, the base is a metatype. - // 2) for a classbound protocol, the base is a class-bound protocol rvalue, - // which is loadable. - // 3) for a mutating method, the base has inout type. - // 4) for a nonmutating method, the base is a general archetype - // rvalue, which is address-only. The base is passed at +0, so it isn't - // consumed. - // - // In the last case, the AST has this call typed as being applied - // to an rvalue, but the witness is actually expecting a pointer - // to the +0 value in memory. We just pass in the address since - // archetypes are address-only. - - assert(!CallSites.empty()); - ApplyExpr *thisCallSite = CallSites.back(); - CallSites.pop_back(); - - ArgumentSource selfValue = thisCallSite->getArg(); - - SubstitutionList subs = e->getDeclRef().getSubstitutions(); - - SILDeclRef::Kind kind = SILDeclRef::Kind::Func; - if (isa(afd)) { - if (proto->isObjC()) { - SILLocation loc = thisCallSite->getArg(); - - // For Objective-C initializers, we only have an initializing - // initializer. We need to allocate the object ourselves. - kind = SILDeclRef::Kind::Initializer; - - auto metatype = std::move(selfValue).getAsSingleValue(SGF); - auto allocated = allocateObjCObject(metatype, loc); - auto allocatedType = allocated.getType().getSwiftRValueType(); - selfValue = ArgumentSource(loc, RValue(SGF, loc, - allocatedType, allocated)); - } else { - // For non-Objective-C initializers, we have an allocating - // initializer to call. - kind = SILDeclRef::Kind::Allocator; - } - } - - SILDeclRef constant = SILDeclRef(afd, kind); - - // Prepare the callee. This can modify both selfValue and subs. - Callee theCallee = Callee::forArchetype(SGF, - selfValue.getSubstRValueType(), - constant, subs, e); - AssumedPlusZeroSelf = selfValue.isRValue() - && selfValue.forceAndPeekRValue(SGF).peekIsPlusZeroRValueOrTrivial(); - - setSelfParam(std::move(selfValue), thisCallSite); - setCallee(std::move(theCallee)); - - return; - } - - if (e->getAccessSemantics() != AccessSemantics::Ordinary) { - isDynamicallyDispatched = false; - } else { - switch (getMethodDispatch(afd)) { - case MethodDispatch::Class: - isDynamicallyDispatched = true; - break; - case MethodDispatch::Static: - isDynamicallyDispatched = false; - break; - } - } - - if (isa(afd) && isDynamicallyDispatched) { - kind = SILDeclRef::Kind::Func; - } else if (auto ctor = dyn_cast(afd)) { - ApplyExpr *thisCallSite = CallSites.back(); - // Required constructors are dynamically dispatched when the 'self' - // value is not statically derived. - if (ctor->isRequired() && - thisCallSite->getArg()->getType()->is() && - !thisCallSite->getArg()->isStaticallyDerivedMetatype()) { - if (requiresForeignEntryPoint(afd)) { - // When we're performing Objective-C dispatch, we don't have an - // allocating constructor to call. So, perform an alloc_ref_dynamic - // and pass that along to the initializer. - requiresAllocRefDynamic = true; - kind = SILDeclRef::Kind::Initializer; - } else { - kind = SILDeclRef::Kind::Allocator; - } - } else { - isDynamicallyDispatched = false; - } - } - - if (isDynamicallyDispatched) { - ApplyExpr *thisCallSite = CallSites.back(); - CallSites.pop_back(); - - // Emit the rvalue for self, allowing for guaranteed plus zero if we - // have a func. - bool AllowPlusZero = kind && *kind == SILDeclRef::Kind::Func; - RValue self = - SGF.emitRValue(thisCallSite->getArg(), - AllowPlusZero ? SGFContext::AllowGuaranteedPlusZero : - SGFContext()); - - // If we allowed for PlusZero and we *did* get the value back at +0, - // then we assumed that self could be passed at +0. We will check later - // if the actual callee passes self at +1 later when we know its actual - // type. - AssumedPlusZeroSelf = - AllowPlusZero && self.peekIsPlusZeroRValueOrTrivial(); - - // If we require a dynamic allocation of the object here, do so now. - if (requiresAllocRefDynamic) { - SILLocation loc = thisCallSite->getArg(); - auto selfValue = allocateObjCObject( - std::move(self).getAsSingleValue(SGF, loc), - loc); - self = RValue(SGF, loc, selfValue.getType().getSwiftRValueType(), - selfValue); - } - - auto selfValue = self.peekScalarValue(); - - setSelfParam(ArgumentSource(thisCallSite->getArg(), std::move(self)), - thisCallSite); - auto constant = SILDeclRef(afd, kind.getValue()) - .asForeign(requiresForeignEntryPoint(afd)); - - auto subs = e->getDeclRef().getSubstitutions(); - setCallee(Callee::forClassMethod(SGF, selfValue, constant, subs, e)); + if (auto *afd = dyn_cast(e->getDecl())) { + // If after processing the abstract function decl, we do not have any more + // work, just return. + if (processAbstractFunctionDecl(e, afd)) { return; } } diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 9acb772dbde..6f09ba4b983 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -546,9 +546,24 @@ struct DelegateInitSelfWritebackCleanup : Cleanup { : loc(loc), lvalueAddress(lvalueAddress), value(value) {} void emit(SILGenFunction &gen, CleanupLocation) override { - gen.emitSemanticStore(loc, value, lvalueAddress, - gen.getTypeLowering(lvalueAddress->getType()), - IsInitialization); + SILValue valueToStore = value; + SILType lvalueObjTy = lvalueAddress->getType().getObjectType(); + + // If we calling a super.init and thus upcasted self, when we store self + // back into the self slot, we need to perform a downcast from the upcasted + // store value to the derived type of our lvalueAddress. + if (valueToStore->getType() != lvalueObjTy) { + if (!valueToStore->getType().isExactSuperclassOf(lvalueObjTy)) { + llvm_unreachable("Invalid usage of delegate init self writeback"); + } + + valueToStore = gen.B.createUncheckedRefCast(loc, valueToStore, + lvalueObjTy); + } + + auto &lowering = gen.B.getTypeLowering(lvalueAddress->getType()); + lowering.emitStore(gen.B, loc, valueToStore, lvalueAddress, + StoreOwnershipQualifier::Init); } void dump(SILGenFunction &gen) const override { @@ -1468,8 +1483,6 @@ ManagedValue emitCFunctionPointer(SILGenFunction &gen, // in the metatype. assert(!declRef.getDecl()->getDeclContext()->isTypeContext() && "c pointers to static methods not implemented"); - assert(declRef.getSubstitutions().empty() - && "c pointers to generics not implemented"); loc = declRef.getDecl(); }; @@ -2780,7 +2793,7 @@ RValue RValueEmitter::visitKeyPathExpr(KeyPathExpr *E, SGFContext C) { auto baseTy = rootTy; for (auto &component : E->getComponents()) { - switch (component.getKind()) { + switch (auto kind = component.getKind()) { case KeyPathExpr::Component::Kind::Property: { auto decl = cast(component.getDeclRef().getDecl()); auto oldBaseTy = baseTy; @@ -2842,12 +2855,34 @@ RValue RValueEmitter::visitKeyPathExpr(KeyPathExpr *E, SGFContext C) { break; } - case KeyPathExpr::Component::Kind::Subscript: case KeyPathExpr::Component::Kind::OptionalChain: case KeyPathExpr::Component::Kind::OptionalForce: - case KeyPathExpr::Component::Kind::OptionalWrap: - return unsupported("non-property key path component"); - + case KeyPathExpr::Component::Kind::OptionalWrap: { + KeyPathPatternComponent::Kind loweredKind; + switch (kind) { + case KeyPathExpr::Component::Kind::OptionalChain: + loweredKind = KeyPathPatternComponent::Kind::OptionalChain; + baseTy = baseTy->getAnyOptionalObjectType()->getCanonicalType(); + break; + case KeyPathExpr::Component::Kind::OptionalForce: + loweredKind = KeyPathPatternComponent::Kind::OptionalForce; + baseTy = baseTy->getAnyOptionalObjectType()->getCanonicalType(); + break; + case KeyPathExpr::Component::Kind::OptionalWrap: + loweredKind = KeyPathPatternComponent::Kind::OptionalWrap; + baseTy = OptionalType::get(baseTy)->getCanonicalType(); + break; + default: + llvm_unreachable("out of sync"); + } + loweredComponents.push_back( + KeyPathPatternComponent::forOptional(loweredKind, baseTy)); + break; + } + + case KeyPathExpr::Component::Kind::Subscript: + return unsupported("subscript key path component"); + case KeyPathExpr::Component::Kind::Invalid: case KeyPathExpr::Component::Kind::UnresolvedProperty: case KeyPathExpr::Component::Kind::UnresolvedSubscript: @@ -2967,7 +3002,7 @@ visitMagicIdentifierLiteralExpr(MagicIdentifierLiteralExpr *E, SGFContext C) { auto DSOGlobal = SGF.SGM.M.lookUpGlobalVariable("__dso_handle"); if (!DSOGlobal) DSOGlobal = SILGlobalVariable::create(SGF.SGM.M, - SILLinkage::HiddenExternal, + SILLinkage::PublicExternal, IsNotSerialized, "__dso_handle", BuiltinRawPtrTy); auto DSOAddr = SGF.B.createGlobalAddr(SILLoc, DSOGlobal); diff --git a/lib/SILGen/SILGenGlobalVariable.cpp b/lib/SILGen/SILGenGlobalVariable.cpp index 6415b16c313..2a93ba8862c 100644 --- a/lib/SILGen/SILGenGlobalVariable.cpp +++ b/lib/SILGen/SILGenGlobalVariable.cpp @@ -47,7 +47,7 @@ SILGlobalVariable *SILGenModule::getSILGlobalVariable(VarDecl *gDecl, SILType silTy = M.Types.getLoweredTypeOfGlobal(gDecl); auto *silGlobal = SILGlobalVariable::create(M, link, - makeModuleFragile + isMakeModuleFragile() ? IsSerialized : IsNotSerialized, mangledName, silTy, @@ -223,7 +223,7 @@ void SILGenModule::emitGlobalInitialization(PatternBindingDecl *pd, // TODO: include the module in the onceToken's name mangling. // Then we can make it fragile. auto onceToken = SILGlobalVariable::create(M, SILLinkage::Private, - makeModuleFragile + isMakeModuleFragile() ? IsSerialized : IsNotSerialized, onceTokenBuffer, onceSILTy); diff --git a/lib/SILGen/SILGenPattern.cpp b/lib/SILGen/SILGenPattern.cpp index 30f751af8ae..c0afb40154c 100644 --- a/lib/SILGen/SILGenPattern.cpp +++ b/lib/SILGen/SILGenPattern.cpp @@ -947,6 +947,7 @@ chooseNecessaryColumn(const ClauseMatrix &matrix, unsigned firstRow) { for (unsigned c = 0; c != numColumns; ++c) { unsigned constructorPrefix = getConstructorPrefix(matrix, firstRow, c); if (constructorPrefix > longestConstructorPrefix) { + longestConstructorPrefix = constructorPrefix; bestColumn = c; } } @@ -2616,7 +2617,7 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) { // We use std::vector because it supports emplace_back; moving a ClauseRow is // expensive. std::vector clauseRows; - clauseRows.reserve(S->getCases().size()); + clauseRows.reserve(S->getRawCases().size()); bool hasFallthrough = false; for (auto caseBlock : S->getCases()) { for (auto &labelItem : caseBlock->getCaseLabelItems()) { diff --git a/lib/SILGen/SILGenStmt.cpp b/lib/SILGen/SILGenStmt.cpp index d76e0dade14..56110a52b9f 100644 --- a/lib/SILGen/SILGenStmt.cpp +++ b/lib/SILGen/SILGenStmt.cpp @@ -200,8 +200,8 @@ void StmtEmitter::visitBraceStmt(BraceStmt *S) { for (auto &ESD : S->getElements()) { - if (auto S = ESD.dyn_cast()) - if (isa(S)) + if (auto D = ESD.dyn_cast()) + if (isa(D)) continue; // If we ever reach an unreachable point, stop emitting statements and issue @@ -541,12 +541,6 @@ void StmtEmitter::visitGuardStmt(GuardStmt *S) { SGF.emitStmtCondition(S->getCond(), bodyBB, S); } - -void StmtEmitter::visitIfConfigStmt(IfConfigStmt *S) { - // Active members are attached to the enclosing declaration, so there's no - // need to walk anything within. -} - void StmtEmitter::visitWhileStmt(WhileStmt *S) { LexicalScope condBufferScope(SGF, S); diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp index 376ad584cc2..c036cc6b69e 100644 --- a/lib/SILGen/SILGenType.cpp +++ b/lib/SILGen/SILGenType.cpp @@ -314,14 +314,14 @@ public: Serialized = IsNotSerialized; // Serialize the witness table if we're serializing everything with - // -sil-serialize-all, or if the conformance itself thinks it should be. - if (SGM.makeModuleFragile) + // -sil-serialize-all.... + if (SGM.isMakeModuleFragile()) Serialized = IsSerialized; - auto *nominal = Conformance->getType()->getAnyNominal(); - if (nominal->hasFixedLayout() && - proto->getEffectiveAccess() >= Accessibility::Public && - nominal->getEffectiveAccess() >= Accessibility::Public) + // ... or if the conformance itself thinks it should be. + if (SILWitnessTable::conformanceIsSerialized( + Conformance, SGM.M.getSwiftModule()->getResilienceStrategy(), + SGM.M.getOptions().SILSerializeWitnessTables)) Serialized = IsSerialized; // Not all protocols use witness tables; in this case we just skip @@ -421,17 +421,9 @@ public: auto witnessLinkage = witnessRef.getLinkage(ForDefinition); auto witnessSerialized = Serialized; if (witnessSerialized && - !hasPublicVisibility(witnessLinkage) && - !hasSharedVisibility(witnessLinkage)) { - // FIXME: This should not happen, but it looks like visibility rules - // for extension members are slightly bogus. - // - // We allow a 'public' member of an extension to witness a public - // protocol requirement, even if the extended type is not public; - // then SILGen gives the member private linkage, ignoring the more - // visible accessibility it was given in the AST. + fixmeWitnessHasLinkageThatNeedsToBePublic(witnessLinkage)) { witnessLinkage = SILLinkage::Public; - witnessSerialized = (SGM.makeModuleFragile + witnessSerialized = (SGM.isMakeModuleFragile() ? IsSerialized : IsNotSerialized); } else { diff --git a/lib/SILOptimizer/Analysis/AccessSummaryAnalysis.cpp b/lib/SILOptimizer/Analysis/AccessSummaryAnalysis.cpp index 48e5ad9e85c..7bbeb0bfc61 100644 --- a/lib/SILOptimizer/Analysis/AccessSummaryAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/AccessSummaryAnalysis.cpp @@ -102,23 +102,68 @@ void AccessSummaryAnalysis::processArgument(FunctionInfo *info, processFullApply(info, argumentIndex, cast(user), operand, order); break; - case ValueKind::CopyAddrInst: - case ValueKind::ExistentialMetatypeInst: - case ValueKind::LoadInst: - case ValueKind::OpenExistentialAddrInst: - case ValueKind::ProjectBlockStorageInst: - // These likely represent scenarios in which we're not generating + default: + // FIXME: These likely represent scenarios in which we're not generating // begin access markers. Ignore these for now. But we really should // add SIL verification to ensure all loads and stores have associated - // access markers. + // access markers. Once SIL verification is implemented, enable the + // following assert to verify that the whitelist above is comprehensive, + // which guarnatees that exclusivity enforcement is complete. + // assert(false && "Unrecognized argument use"); break; - default: - // TODO: These requirements should be checked for in the SIL verifier. - llvm_unreachable("Unrecognized argument use"); } } } +#ifndef NDEBUG +/// Sanity check to make sure that a noescape partial apply is +/// only ultimately used by an apply, a try_apply or as an argument (but not +/// the called function) in a partial_apply. +/// +/// FIXME: This needs to be checked in the SILVerifier. +static bool hasExpectedUsesOfNoEscapePartialApply(Operand *partialApplyUse) { + SILInstruction *user = partialApplyUse->getUser(); + + // It is fine to call the partial apply + switch (user->getKind()) { + case ValueKind::ApplyInst: + case ValueKind::TryApplyInst: + return true; + + case ValueKind::ConvertFunctionInst: + return llvm::all_of(user->getUses(), + hasExpectedUsesOfNoEscapePartialApply); + + case ValueKind::PartialApplyInst: + return partialApplyUse->get() != cast(user)->getCallee(); + + case ValueKind::StoreInst: + case ValueKind::DestroyValueInst: + // @block_storage is passed by storing it to the stack. We know this is + // still nonescaping simply because our original argument convention is + // @inout_aliasable. In this SIL, both store and destroy_value are users + // of %closure: + // + // %closure = partial_apply %f1(%arg) + // : $@convention(thin) (@inout_aliasable T) -> () + // %storage = alloc_stack $@block_storage @callee_owned () -> () + // %block_addr = project_block_storage %storage + // : $*@block_storage @callee_owned () -> () + // store %closure to [init] %block_addr : $*@callee_owned () -> () + // %block = init_block_storage_header %storage + // : $*@block_storage @callee_owned () -> (), + // invoke %f2 : $@convention(c) + // (@inout_aliasable @block_storage @callee_owned () -> ()) -> (), + // type $@convention(block) () -> () + // %copy = copy_block %block : $@convention(block) () -> () + // destroy_value %storage : $@callee_owned () -> () + return true; + default: + return false; + } +} +#endif + void AccessSummaryAnalysis::processPartialApply(FunctionInfo *callerInfo, unsigned callerArgumentIndex, PartialApplyInst *apply, @@ -133,29 +178,16 @@ void AccessSummaryAnalysis::processPartialApply(FunctionInfo *callerInfo, assert(isa(apply->getCallee()) && "Noescape partial apply of non-functionref?"); - // Make sure the partial_apply is used by an apply and not another - // partial_apply - SILInstruction *user = apply->getSingleUse()->getUser(); - assert((isa(user) || isa(user) || - isa(user)) && - "noescape partial_apply has non-apply use!"); - (void)user; - - // The arguments to partial_apply are a suffix of the arguments to the - // the actually-called function. Translate the index of the argument to - // the partial_apply into to the corresponding index into the arguments of - // the called function. - - // The first operand to partial_apply is the called function, so adjust the - // operand number to get the argument. - unsigned partialApplyArgumentIndex = - applyArgumentOperand->getOperandNumber() - 1; + assert(llvm::all_of(apply->getUses(), + hasExpectedUsesOfNoEscapePartialApply) && + "noescape partial_apply has unexpected use!"); // The argument index in the called function. - unsigned argumentIndex = calleeFunction->getArguments().size() - - apply->getNumArguments() + partialApplyArgumentIndex; - processCall(callerInfo, callerArgumentIndex, calleeFunction, argumentIndex, - order); + ApplySite site(apply); + unsigned calleeArgumentIndex = site.getCalleeArgIndex(*applyArgumentOperand); + + processCall(callerInfo, callerArgumentIndex, calleeFunction, + calleeArgumentIndex, order); } void AccessSummaryAnalysis::processFullApply(FunctionInfo *callerInfo, @@ -301,6 +333,8 @@ AccessSummaryAnalysis::getOrCreateSummary(SILFunction *fn) { void AccessSummaryAnalysis::AccessSummaryAnalysis::invalidate() { FunctionInfos.clear(); Allocator.DestroyAll(); + delete SubPathTrie; + SubPathTrie = new IndexTrieNode(); } void AccessSummaryAnalysis::invalidate(SILFunction *F, InvalidationKind K) { diff --git a/lib/SILOptimizer/Analysis/CMakeLists.txt b/lib/SILOptimizer/Analysis/CMakeLists.txt index fd68ea98e82..b6f4fc42caa 100644 --- a/lib/SILOptimizer/Analysis/CMakeLists.txt +++ b/lib/SILOptimizer/Analysis/CMakeLists.txt @@ -8,6 +8,7 @@ set(ANALYSIS_SOURCES Analysis/CallerAnalysis.cpp Analysis/CFG.cpp Analysis/ClassHierarchyAnalysis.cpp + Analysis/ClosureScope.cpp Analysis/ColdBlockInfo.cpp Analysis/DestructorAnalysis.cpp Analysis/EscapeAnalysis.cpp diff --git a/lib/SILOptimizer/Analysis/ClosureScope.cpp b/lib/SILOptimizer/Analysis/ClosureScope.cpp new file mode 100644 index 00000000000..fc07cfaefb0 --- /dev/null +++ b/lib/SILOptimizer/Analysis/ClosureScope.cpp @@ -0,0 +1,201 @@ +//===--- ClosureScope.cpp - Closure Scope Analysis ------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +/// +/// Implementation of ClosureScopeAnalysis. +/// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "closure-scope" + +#include "swift/SIL/SILModule.h" +#include "swift/SILOptimizer/Analysis/ClosureScope.h" + +namespace swift { + +class ClosureScopeData { + using IndexRange = ClosureScopeAnalysis::IndexRange; + using IndexLookupFunc = ClosureScopeAnalysis::IndexLookupFunc; + using ScopeRange = ClosureScopeAnalysis::ScopeRange; + +private: + // Map an index to each SILFunction with a closure scope. + std::vector indexedScopes; + + // Map each SILFunction with a closure scope to an index. + llvm::DenseMap scopeToIndexMap; + + // A list of all indices for the SILFunctions that partially apply this + // closure. The indices index into the `indexedScopes` vector. If the indexed + // scope is nullptr, then that function has been deleted. + using ClosureScopes = llvm::SmallVector; + + // Map each closure to its parent scopes. + llvm::DenseMap closureToScopesMap; + +public: + void reset() { + indexedScopes.clear(); + scopeToIndexMap.clear(); + closureToScopesMap.clear(); + } + + void erase(SILFunction *F) { + // If this function is a mapped closure scope, remove it, leaving a nullptr + // sentinel. + auto indexPos = scopeToIndexMap.find(F); + if (indexPos != scopeToIndexMap.end()) { + indexedScopes[indexPos->second] = nullptr; + scopeToIndexMap.erase(F); + } + // If this function is a closure, remove it. + closureToScopesMap.erase(F); + } + + // Record all closure scopes in this module. + void compute(SILModule *M); + + bool isClosureScope(SILFunction *F) { return scopeToIndexMap.count(F); } + + // Return a range of scopes for the given closure. The elements of the + // returned range have type `SILFunction *` and are non-null. Return an empty + // range for a SILFunction that is not a closure or is a dead closure. + ScopeRange getClosureScopes(SILFunction *ClosureF) { + IndexRange indexRange(nullptr, nullptr); + auto closureScopesPos = closureToScopesMap.find(ClosureF); + if (closureScopesPos != closureToScopesMap.end()) { + auto &indexedScopes = closureScopesPos->second; + indexRange = IndexRange(indexedScopes.begin(), indexedScopes.end()); + } + return makeOptionalTransformRange(indexRange, + IndexLookupFunc(indexedScopes)); + } + + void recordScope(PartialApplyInst *PAI) { + // Only track scopes of non-escaping closures. + auto closureTy = PAI->getCallee()->getType().castTo(); + if (!isNonEscapingClosure(closureTy)) + return; + + auto closureFunc = PAI->getCalleeFunction(); + assert(closureFunc && "non-escaping closure needs a direct partial_apply."); + + auto scopeFunc = PAI->getFunction(); + int scopeIdx = lookupScopeIndex(scopeFunc); + + auto &indices = closureToScopesMap[closureFunc]; + if (std::find(indices.begin(), indices.end(), scopeIdx) != indices.end()) + return; + + indices.push_back(scopeIdx); + } + +protected: + int lookupScopeIndex(SILFunction *scopeFunc) { + auto indexPos = scopeToIndexMap.find(scopeFunc); + if (indexPos != scopeToIndexMap.end()) + return indexPos->second; + + int scopeIdx = indexedScopes.size(); + scopeToIndexMap[scopeFunc] = scopeIdx; + indexedScopes.push_back(scopeFunc); + return scopeIdx; + } +}; + +void ClosureScopeData::compute(SILModule *M) { + for (auto &F : *M) { + for (auto &BB : F) { + for (auto &I : BB) { + if (auto *PAI = dyn_cast(&I)) { + recordScope(PAI); + } + } + } + } +} + +ClosureScopeAnalysis::ClosureScopeAnalysis(SILModule *M) + : SILAnalysis(AnalysisKind::ClosureScope), M(M), scopeData(nullptr) {} + +ClosureScopeAnalysis::~ClosureScopeAnalysis() = default; + +bool ClosureScopeAnalysis::isClosureScope(SILFunction *scopeFunc) { + return getOrComputeScopeData()->isClosureScope(scopeFunc); +} + +ClosureScopeAnalysis::ScopeRange +ClosureScopeAnalysis::getClosureScopes(SILFunction *closureFunc) { + return getOrComputeScopeData()->getClosureScopes(closureFunc); +} + +void ClosureScopeAnalysis::invalidate() { + if (scopeData) scopeData->reset(); +} + +void ClosureScopeAnalysis::notifyDeleteFunction(SILFunction *F) { + if (scopeData) scopeData->erase(F); +} + +ClosureScopeData *ClosureScopeAnalysis::getOrComputeScopeData() { + if (!scopeData) { + scopeData = llvm::make_unique(); + scopeData->compute(M); + } + return scopeData.get(); +} + +SILAnalysis *createClosureScopeAnalysis(SILModule *M) { + return new ClosureScopeAnalysis(M); +} + +void TopDownClosureFunctionOrder::visitFunctions( + std::function visitor) { + auto markVisited = [&](SILFunction *F) { + bool visitOnce = visited.insert(F).second; + assert(visitOnce); + (void)visitOnce; + }; + auto allScopesVisited = [&](SILFunction *closureF) { + return llvm::all_of(CSA->getClosureScopes(closureF), + [this](SILFunction *F) { return visited.count(F); }); + }; + for (auto &F : *CSA->getModule()) { + if (!allScopesVisited(&F)) { + closureWorklist.insert(&F); + continue; + } + markVisited(&F); + visitor(&F); + } + unsigned numClosures = closureWorklist.size(); + while (numClosures) { + unsigned prevNumClosures = numClosures; + for (auto &closureNode : closureWorklist) { + // skip erased closures. + if (!closureNode) + continue; + + auto closureF = closureNode.getValue(); + if (!allScopesVisited(closureF)) + continue; + + markVisited(closureF); + visitor(closureF); + closureWorklist.erase(closureF); + --numClosures; + } + assert(numClosures < prevNumClosures && "Cyclic closures scopes"); + (void)prevNumClosures; + } +} + +} // namespace swift diff --git a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp index c38125b7919..e4477a1d297 100644 --- a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp +++ b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp @@ -226,6 +226,9 @@ protected: continue; } case KeyPathPatternComponent::Kind::StoredProperty: + case KeyPathPatternComponent::Kind::OptionalChain: + case KeyPathPatternComponent::Kind::OptionalForce: + case KeyPathPatternComponent::Kind::OptionalWrap: continue; } } diff --git a/lib/SILOptimizer/Mandatory/AccessEnforcementSelection.cpp b/lib/SILOptimizer/Mandatory/AccessEnforcementSelection.cpp index 9c08837260a..7b56b88e96d 100644 --- a/lib/SILOptimizer/Mandatory/AccessEnforcementSelection.cpp +++ b/lib/SILOptimizer/Mandatory/AccessEnforcementSelection.cpp @@ -13,6 +13,20 @@ /// This pass eliminates 'unknown' access enforcement by selecting either /// static or dynamic enforcement. /// +/// TODO: This is currently a module transform so that closures can be +/// transformed after their parent scope is analyzed. This isn't a big problem +/// now because AccessMarkerElimination is also a module pass that follows this +/// pass. However, we would like to mostly eliminate module transforms. This +/// could be done by changing the PassManager to follow CloseScopeAnalysis. A +/// new ClosureTransform type would be pipelined just like FunctionTransform, +/// but would have an entry point that handled a parent closure scope and all +/// its children in one invocation. For function pipelining to be upheld, we +/// would need to verify that BasicCalleeAnalysis never conflicts with +/// ClosureScopeAnalysis. i.e. we could never create a caller->callee edge when +/// the callee is passed as a function argument. Normal FunctionTransforms would +/// then be called on each closure function and its parent scope before calling +/// the ClosureTransform. +/// /// FIXME: handle boxes used by copy_value when neither copy is captured. /// //===----------------------------------------------------------------------===// @@ -21,6 +35,7 @@ #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILUndef.h" +#include "swift/SILOptimizer/Analysis/ClosureScope.h" #include "swift/SILOptimizer/PassManager/Transforms.h" using namespace swift; @@ -39,8 +54,82 @@ static void setDynamicEnforcement(BeginAccessInst *access) { DEBUG(llvm::dbgs() << "Dynamic Access: " << *access); } +namespace { +// Information about an address-type closure capture. +// This is only valid for inout_aliasable parameters. +// +// TODO: Verify somewhere that we properly handle any non-inout_aliasable +// partial apply captures or that they never happen. Eventually @inout_aliasable +// should be simply replaced by @in or @out, once we don't have special aliasing +// rules. +struct AddressCapture { + ApplySite site; + unsigned calleeArgIdx; + + AddressCapture(Operand &oper) + : site(oper.getUser()), calleeArgIdx(site.getCalleeArgIndex(oper)) { + assert(isa(site)); + if (site.getOrigCalleeConv().getSILArgumentConvention(calleeArgIdx) + != SILArgumentConvention::Indirect_InoutAliasable) { + site = ApplySite(); + calleeArgIdx = ~0U; + return; + } + assert(oper.get()->getType().isAddress()); + } + + bool isValid() const { return bool(site); } +}; + +raw_ostream &operator<<(raw_ostream &os, const AddressCapture &capture) { + os << *capture.site.getInstruction() << " captures Arg #" + << capture.calleeArgIdx; + auto *F = capture.site.getCalleeFunction(); + if (F) + os << " of " << F->getName(); + os << '\n'; + return os; +} + +// For each non-escaping closure, record the indices of arguments that +// require dynamic enforcement. +class DynamicCaptures { + llvm::DenseMap> dynamicCaptureMap; + + DynamicCaptures(DynamicCaptures &) = delete; + +public: + DynamicCaptures() = default; + + void recordCapture(AddressCapture capture) { + DEBUG(llvm::dbgs() << "Dynamic Capture: " << capture); + + auto callee = capture.site.getCalleeFunction(); + assert(callee && "cannot locate function ref for nonescaping closure"); + + auto &dynamicArgs = dynamicCaptureMap[callee]; + if (!llvm::is_contained(dynamicArgs, capture.calleeArgIdx)) + dynamicArgs.push_back(capture.calleeArgIdx); + } + + bool isDynamic(SILFunctionArgument *arg) const { + auto pos = dynamicCaptureMap.find(arg->getFunction()); + if (pos == dynamicCaptureMap.end()) + return false; + + auto &dynamicArgs = pos->second; + return llvm::is_contained(dynamicArgs, arg->getIndex()); + } +}; +} // anonymous namespace + namespace { class SelectEnforcement { + // Reference back to the known dynamically enforced non-escaping closure + // arguments in this module. Parent scopes are processed before the closures + // they reference. + DynamicCaptures &dynamicCaptures; + AllocBoxInst *Box; /// A state for tracking escape information about a variable. @@ -67,9 +156,12 @@ class SelectEnforcement { }; llvm::DenseMap StateMap; - /// All the accesses in the function. + /// All the accesses of Box in the function. SmallVector Accesses; + /// All the non-escaping closure captures of the Boxed value in this function. + SmallVector Captures; + /// All the escapes in the function. SmallPtrSet Escapes; @@ -77,7 +169,8 @@ class SelectEnforcement { SmallVector Worklist; public: - SelectEnforcement(AllocBoxInst *box) : Box(box) {} + SelectEnforcement(DynamicCaptures &dc, AllocBoxInst *box) + : dynamicCaptures(dc), Box(box) {} void run(); @@ -102,10 +195,13 @@ private: void updateAccesses(); void updateAccess(BeginAccessInst *access); + void updateCapture(AddressCapture capture); }; } // end anonymous namespace void SelectEnforcement::run() { + DEBUG(llvm::dbgs() << " Box: " << *Box); + // Set up the data-flow problem. analyzeUsesOfBox(Box); @@ -143,23 +239,29 @@ void SelectEnforcement::analyzeUsesOfBox(SILInstruction *source) { // Treat everything else as an escape: noteEscapingUse(user); } - - assert(!Accesses.empty() && "didn't find original access!"); + // Accesses may still be empty if the user of the Box is a partial apply + // capture and, for some reason, the closure is dead. } void SelectEnforcement::analyzeProjection(ProjectBoxInst *projection) { - for (auto use : projection->getUses()) { + for (auto *use : projection->getUses()) { auto user = use->getUser(); // Collect accesses. - if (auto access = dyn_cast(user)) { + if (auto *access = dyn_cast(user)) { if (access->getEnforcement() == SILAccessEnforcement::Unknown) Accesses.push_back(access); + + continue; } + if (auto *PAI = dyn_cast(user)) + Captures.emplace_back(AddressCapture(*use)); } } void SelectEnforcement::noteEscapingUse(SILInstruction *inst) { + DEBUG(llvm::dbgs() << " Escape: " << *inst); + // Add it to the escapes set. Escapes.insert(inst); @@ -302,9 +404,14 @@ bool SelectEnforcement::hasPotentiallyEscapedAtAnyReachableBlock( } void SelectEnforcement::updateAccesses() { - for (auto access : Accesses) { + for (auto *access : Accesses) { + DEBUG(llvm::dbgs() << " Access: " << *access); updateAccess(access); } + for (AddressCapture &capture : Captures) { + DEBUG(llvm::dbgs() << " Capture: " << capture); + updateCapture(capture); + } } void SelectEnforcement::updateAccess(BeginAccessInst *access) { @@ -326,98 +433,238 @@ void SelectEnforcement::updateAccess(BeginAccessInst *access) { // For every path through this access that doesn't reach an end_access, check // if any block reachable from that path can see an escaped value. if (hasPotentiallyEscapedAtAnyReachableBlock(access, blocksAccessedAcross)) { - return setDynamicEnforcement(access); + setDynamicEnforcement(access); + return; } // Otherwise, use static enforcement. setStaticEnforcement(access); } +void SelectEnforcement::updateCapture(AddressCapture capture) { + llvm::SmallSetVector worklist; + auto visitUse = [&](Operand *oper) { + if (FullApplySite::isa(oper->getUser())) { + // A call is considered a closure access regardless of whether it calls + // the closure or accepts the closure as an argument. + if (hasPotentiallyEscapedAt(oper->getUser())) { + dynamicCaptures.recordCapture(capture); + return; + } + } + if (auto *PAI = dyn_cast(oper->getUser())) { + assert(oper->get() != PAI->getCallee() && "cannot re-partially apply"); + // The closure is capture by another closure. Transitively consider any + // calls to the parent closure as an access. + worklist.insert(PAI); + } + }; + auto *PAI = dyn_cast(capture.site); + while (true) { + for (auto *oper : PAI->getUses()) + visitUse(oper); + if (worklist.empty()) + break; + PAI = worklist.pop_back_val(); + } +} + namespace { -/// The pass. -struct AccessEnforcementSelection : SILFunctionTransform { - void run() override { - DEBUG(llvm::dbgs() << "Access Enforcement Selection in " - << getFunction()->getName() << "\n"); +// Model the kind of access needed based on analyzing the access's source. +// This is either determined to be static or dynamic, or requires further +// analysis of a boxed variable. +struct SourceAccess { + enum { StaticAccess, DynamicAccess, BoxAccess } kind; + AllocBoxInst *allocBox; - for (auto &bb : *getFunction()) { - for (auto ii = bb.begin(), ie = bb.end(); ii != ie; ) { - SILInstruction *inst = &*ii; - ++ii; + static SourceAccess getStaticAccess() { return {StaticAccess, nullptr}; } + static SourceAccess getDynamicAccess() { return {DynamicAccess, nullptr}; } - if (auto access = dyn_cast(inst)) - handleAccess(access); - - if (auto access = dyn_cast(inst)) - assert(access->getEnforcement() == SILAccessEnforcement::Dynamic); - } - } - invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions); - } - - void handleAccess(BeginAccessInst *access) { - if (access->getEnforcement() != SILAccessEnforcement::Unknown) - return; - - auto address = access->getOperand(); - assert(!isa(address) && - "pass should be run after definite initialization"); - - if (auto box = dyn_cast(address)) { - return handleAccessToBox(access, box); - } - if (auto arg = dyn_cast(address)) { - switch (arg->getArgumentConvention()) { - case SILArgumentConvention::Indirect_Inout: - case SILArgumentConvention::Indirect_InoutAliasable: - // `inout` arguments are checked on the caller side, either statically - // or dynamically if necessary. The @inout does not alias and cannot - // escape within the callee, so static enforcement is always sufficient. - // - // FIXME: `inout_aliasable` are not currently enforced on the caller - // side. Consequently, using static enforcement for noescape closures - // may fails to diagnose certain violations. - setStaticEnforcement(access); - break; - default: - // @in/@in_guaranteed cannot be mutably accessed, mutably captured, or - // passed as inout. - // - // FIXME: When we have borrowed arguments, a "read" needs to be enforced - // on the caller side. - llvm_unreachable("Expecting an inout argument."); - } - return; - } - - // If we're not accessing a box or argument, we must've lowered to a stack - // element. Other sources of access are either outright dynamic (GlobalAddr, - // RefElementAddr), or only exposed after mandatory inlining (nested - // dependent BeginAccess). - // - // Running before diagnostic constant propagation requires handling 'undef'. - assert(isa(address) || isa(address)); - setStaticEnforcement(access); - } - - void handleAccessToBox(BeginAccessInst *access, ProjectBoxInst *projection) { - SILValue source = projection->getOperand(); - if (auto *MUI = dyn_cast(source)) - source = MUI->getOperand(); - - // If we didn't allocate the box, assume that we need to use - // dynamic enforcement. - // TODO: use static enforcement in certain provable cases. - auto box = dyn_cast(source); - if (!box) { - setDynamicEnforcement(access); - return; - } - - SelectEnforcement(box).run(); + static SourceAccess getBoxedAccess(AllocBoxInst *inst) { + return {BoxAccess, inst}; } }; +/// The pass. +class AccessEnforcementSelection : public SILModuleTransform { + // Reference back to the known dynamically enforced non-escaping closure + // arguments in this module. Parent scopes are processed before the closures + // they reference. + DynamicCaptures dynamicCaptures; + + // Per-function book-keeping. A box is processed the first time one of it's + // accesses is handled. Don't process it again for subsequent accesses. + llvm::DenseSet handledBoxes; + +#ifndef NDEBUG + llvm::DenseSet visited; +#endif + +public: + void run() override; + +protected: + void processFunction(SILFunction *F); + SourceAccess getAccessKindForBox(ProjectBoxInst *projection); + SourceAccess getSourceAccess(SILValue address); + void handlePartialApply(PartialApplyInst *PAI); + void handleAccess(BeginAccessInst *access); +}; + +void AccessEnforcementSelection::run() { + auto *CSA = getAnalysis(); + TopDownClosureFunctionOrder closureOrder(CSA); + closureOrder.visitFunctions( + [this](SILFunction *F) { this->processFunction(F); }); +} + +void AccessEnforcementSelection::processFunction(SILFunction *F) { + DEBUG(llvm::dbgs() << "Access Enforcement Selection in " << F->getName() + << "\n"); +#ifndef NDEBUG + auto *CSA = getAnalysis(); + if (isNonEscapingClosure(F->getLoweredFunctionType())) { + for (auto *scopeF : CSA->getClosureScopes(F)) { + DEBUG(llvm::dbgs() << " Parent scope: " << scopeF->getName() << "\n"); + assert(visited.count(scopeF)); + } + } + visited.insert(F); +#endif + + for (auto &bb : *F) { + for (auto ii = bb.begin(), ie = bb.end(); ii != ie;) { + SILInstruction *inst = &*ii; + ++ii; + + if (auto access = dyn_cast(inst)) + handleAccess(access); + + else if (auto access = dyn_cast(inst)) + assert(access->getEnforcement() == SILAccessEnforcement::Dynamic); + + else if(auto pa = dyn_cast(inst)) + handlePartialApply(pa); + } + } + invalidateAnalysis(F, SILAnalysis::InvalidationKind::Instructions); + // There's no need to track handled boxes across functions. + handledBoxes.clear(); +} + +SourceAccess +AccessEnforcementSelection::getAccessKindForBox(ProjectBoxInst *projection) { + SILValue source = projection->getOperand(); + if (auto *MUI = dyn_cast(source)) + source = MUI->getOperand(); + + // If we didn't allocate the box, assume that we need to use + // dynamic enforcement. + // TODO: use static enforcement in certain provable cases. + auto box = dyn_cast(source); + if (!box) + return SourceAccess::getDynamicAccess(); + + return SourceAccess::getBoxedAccess(box); +} + +SourceAccess AccessEnforcementSelection::getSourceAccess(SILValue address) { + // Recurse through MarkUninitializedInst. + if (auto *MUI = dyn_cast(address)) + return getSourceAccess(MUI->getOperand()); + + if (auto box = dyn_cast(address)) + return getAccessKindForBox(box); + + if (auto arg = dyn_cast(address)) { + switch (arg->getArgumentConvention()) { + case SILArgumentConvention::Indirect_Inout: + // `inout` arguments are checked on the caller side, either statically + // or dynamically if necessary. The @inout does not alias and cannot + // escape within the callee, so static enforcement is always sufficient. + return SourceAccess::getStaticAccess(); + + case SILArgumentConvention::Indirect_InoutAliasable: + if (dynamicCaptures.isDynamic(arg)) + return SourceAccess::getDynamicAccess(); + + return SourceAccess::getStaticAccess(); + case SILArgumentConvention::Indirect_In: + case SILArgumentConvention::Indirect_In_Guaranteed: + // @in/@in_guaranteed cannot be mutably accessed, mutably captured, or + // passed as inout. @in/@in_guaranteed may be captured @inout_aliasable. + // (This is fairly horrible, but presumably Sema/SILGen made sure a copy + // wasn't needed?) + // + // FIXME: When we have borrowed arguments, a "read" needs to be enforced + // on the caller side. + return SourceAccess::getStaticAccess(); + + default: + llvm_unreachable("Expecting an inout argument."); + } + } + // If we're not accessing a box or argument, we must've lowered to a stack + // element. Other sources of access are either outright dynamic (GlobalAddr, + // RefElementAddr), or only exposed after mandatory inlining (nested + // dependent BeginAccess). + // + // Running before diagnostic constant propagation requires handling 'undef'. + assert(isa(address) || isa(address)); + return SourceAccess::getStaticAccess(); +} + +void AccessEnforcementSelection::handlePartialApply(PartialApplyInst *PAI) { + ApplySite site(PAI); + auto calleeTy = PAI->getOrigCalleeType(); + SILFunctionConventions calleeConv(calleeTy, *getModule()); + + for (Operand &oper : site.getArgumentOperands()) { + AddressCapture capture(oper); + if (!capture.isValid()) + continue; + + // This partial apply creates a non-escaping closure. Check if the closure + // captures any Boxed variables from this scope. If so, check if the box + // escapes before the access just as we do for normal accesses. + auto sourceAccess = getSourceAccess(oper.get()); + switch (sourceAccess.kind) { + case SourceAccess::StaticAccess: + // If the captured variable does not require dynamic enforcement, then + // there's no need to track it. + break; + case SourceAccess::DynamicAccess: { + dynamicCaptures.recordCapture(capture); + break; + } + case SourceAccess::BoxAccess: + if (handledBoxes.insert(sourceAccess.allocBox).second) + SelectEnforcement(dynamicCaptures, sourceAccess.allocBox).run(); + break; + } + } +} + +void AccessEnforcementSelection::handleAccess(BeginAccessInst *access) { + if (access->getEnforcement() != SILAccessEnforcement::Unknown) + return; + + auto sourceAccess = getSourceAccess(access->getOperand()); + switch (sourceAccess.kind) { + case SourceAccess::StaticAccess: + setStaticEnforcement(access); + break; + case SourceAccess::DynamicAccess: + setDynamicEnforcement(access); + break; + case SourceAccess::BoxAccess: + // If this box was handled, the access enforcement would already be set. + assert(!handledBoxes.count(sourceAccess.allocBox)); + SelectEnforcement(dynamicCaptures, sourceAccess.allocBox).run(); + break; + } +} + } // end anonymous namespace SILTransform *swift::createAccessEnforcementSelection() { diff --git a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp index 52389736d46..54b93866b4a 100644 --- a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp +++ b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp @@ -257,12 +257,11 @@ ValueDecl *DIMemoryObjectInfo:: getPathStringToElement(unsigned Element, std::string &Result) const { auto &Module = MemoryInst->getModule(); - // TODO: Handle special names if (isAnyInitSelf()) Result = "self"; else if (ValueDecl *VD = dyn_cast_or_null(getLoc().getAsASTNode())) - Result = VD->getBaseName().getIdentifier().str(); + Result = VD->getBaseName().userFacingName(); else Result = ""; diff --git a/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp b/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp index b1059bf41cb..3d89887669e 100644 --- a/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp +++ b/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp @@ -35,6 +35,7 @@ #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/Projection.h" +#include "swift/SILOptimizer/Analysis/AccessSummaryAnalysis.h" #include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" @@ -162,32 +163,81 @@ public: } }; +enum class RecordedAccessKind { + /// The access was for a 'begin_access' instruction in the current function + /// being checked. + BeginInstruction, + + /// The access was inside noescape closure that we either + /// passed to function or called directly. It results from applying the + /// the summary of the closure to the closure's captures. + NoescapeClosureCapture +}; + /// Records an access to an address and the single subpath of projections /// that was performed on the address, if such a single subpath exists. class RecordedAccess { private: - BeginAccessInst *Inst; - ProjectionPath SubPath; + RecordedAccessKind RecordKind; + union { + BeginAccessInst *Inst; + struct { + SILAccessKind ClosureAccessKind; + SILLocation ClosureAccessLoc; + }; + }; + const IndexTrieNode *SubPath; public: - RecordedAccess(BeginAccessInst *BAI, const ProjectionPath &SubPath) - : Inst(BAI), SubPath(SubPath) {} + RecordedAccess(BeginAccessInst *BAI, const IndexTrieNode *SubPath) : + RecordKind(RecordedAccessKind::BeginInstruction), Inst(BAI), + SubPath(SubPath) { } - BeginAccessInst *getInstruction() const { return Inst; } + RecordedAccess(SILAccessKind ClosureAccessKind, + SILLocation ClosureAccessLoc, const IndexTrieNode *SubPath) : + RecordKind(RecordedAccessKind::NoescapeClosureCapture), + ClosureAccessKind(ClosureAccessKind), ClosureAccessLoc(ClosureAccessLoc), + SubPath(SubPath) { } - SILAccessKind getAccessKind() const { return Inst->getAccessKind(); } + RecordedAccessKind getRecordKind() const { + return RecordKind; + } - SILLocation getAccessLoc() const { return Inst->getLoc(); } + BeginAccessInst *getInstruction() const { + assert(RecordKind == RecordedAccessKind::BeginInstruction); + return Inst; + } - const ProjectionPath &getSubPath() const { return SubPath; } + SILAccessKind getAccessKind() const { + switch (RecordKind) { + case RecordedAccessKind::BeginInstruction: + return Inst->getAccessKind(); + case RecordedAccessKind::NoescapeClosureCapture: + return ClosureAccessKind; + }; + } + + SILLocation getAccessLoc() const { + switch (RecordKind) { + case RecordedAccessKind::BeginInstruction: + return Inst->getLoc(); + case RecordedAccessKind::NoescapeClosureCapture: + return ClosureAccessLoc; + }; + } + + const IndexTrieNode *getSubPath() const { + return SubPath; + } }; + /// Records the in-progress accesses to a given sub path. class SubAccessInfo { public: - SubAccessInfo(const ProjectionPath &P) : Path(P) {} + SubAccessInfo(const IndexTrieNode *P) : Path(P) {} - ProjectionPath Path; + const IndexTrieNode *Path; /// The number of in-progress 'read' accesses (that is 'begin_access [read]' /// instructions that have not yet had the corresponding 'end_access'). @@ -202,7 +252,7 @@ public: public: /// Increment the count for given access. - void beginAccess(BeginAccessInst *BAI, const ProjectionPath &SubPath) { + void beginAccess(BeginAccessInst *BAI, const IndexTrieNode *SubPath) { if (!FirstAccess) { assert(Reads == 0 && NonReads == 0); FirstAccess = RecordedAccess(BAI, SubPath); @@ -250,14 +300,17 @@ public: } bool conflictsWithAccess(SILAccessKind Kind, - const ProjectionPath &SubPath) const { + const IndexTrieNode *SubPath) const { if (!canConflictWithAccessOfKind(Kind)) return false; - SubSeqRelation_t Relation = Path.computeSubSeqRelation(SubPath); - // If the one path is a subsequence of the other (or they are the same) - // then access the same storage. - return (Relation != SubSeqRelation_t::Unknown); + return pathsConflict(Path, SubPath); + } + + /// Returns true when the two subpaths access overlapping memory. + bool pathsConflict(const IndexTrieNode *Path1, + const IndexTrieNode *Path2) const { + return Path1->isPrefixOf(Path2) || Path2->isPrefixOf(Path1); } }; @@ -271,7 +324,7 @@ class AccessInfo { SubAccessVector SubAccesses; /// Returns the SubAccess info for accessing at the given SubPath. - SubAccessInfo &findOrCreateSubAccessInfo(const ProjectionPath &SubPath) { + SubAccessInfo &findOrCreateSubAccessInfo(const IndexTrieNode *SubPath) { for (auto &Info : SubAccesses) { if (Info.Path == SubPath) return Info; @@ -283,7 +336,7 @@ class AccessInfo { SubAccessVector::const_iterator findFirstSubPathWithConflict(SILAccessKind OtherKind, - const ProjectionPath &OtherSubPath) const { + const IndexTrieNode *OtherSubPath) const { // Note this iteration requires deterministic ordering for repeatable // diagnostics. for (auto I = SubAccesses.begin(), E = SubAccesses.end(); I != E; ++I) { @@ -299,7 +352,7 @@ public: // Returns the previous access when beginning an access of the given Kind will // result in a conflict with a previous access. Optional - conflictsWithAccess(SILAccessKind Kind, const ProjectionPath &SubPath) const { + conflictsWithAccess(SILAccessKind Kind, const IndexTrieNode *SubPath) const { auto I = findFirstSubPathWithConflict(Kind, SubPath); if (I == SubAccesses.end()) return None; @@ -326,13 +379,13 @@ public: } /// Increment the count for given access. - void beginAccess(BeginAccessInst *BAI, const ProjectionPath &SubPath) { + void beginAccess(BeginAccessInst *BAI, const IndexTrieNode *SubPath) { SubAccessInfo &SubAccess = findOrCreateSubAccessInfo(SubPath); SubAccess.beginAccess(BAI, SubPath); } /// Decrement the count for given access. - void endAccess(EndAccessInst *EAI, const ProjectionPath &SubPath) { + void endAccess(EndAccessInst *EAI, const IndexTrieNode *SubPath) { SubAccessInfo &SubAccess = findOrCreateSubAccessInfo(SubPath); SubAccess.endAccess(EAI); } @@ -580,36 +633,45 @@ tryFixItWithCallToCollectionSwapAt(const BeginAccessInst *Access1, /// that stored-property relaxation supports: struct stored properties /// and tuple elements. static std::string getPathDescription(DeclName BaseName, SILType BaseType, - ProjectionPath SubPath, SILModule &M) { + const IndexTrieNode *SubPath, + SILModule &M) { + // Walk the trie to the root to collection the sequence (in reverse order). + llvm::SmallVector ReversedIndices; + const IndexTrieNode *I = SubPath; + while (!I->isRoot()) { + ReversedIndices.push_back(I->getIndex()); + I = I->getParent(); + } + std::string sbuf; llvm::raw_string_ostream os(sbuf); os << "'" << BaseName; SILType ContainingType = BaseType; - for (auto &P : SubPath) { + for (unsigned Index : reversed(ReversedIndices)) { os << "."; - switch (P.getKind()) { - case ProjectionKind::Struct: - os << P.getVarDecl(ContainingType)->getBaseName(); - break; - case ProjectionKind::Tuple: { - // Use the tuple element's name if present, otherwise use its index. - Type SwiftTy = ContainingType.getSwiftRValueType(); - TupleType *TupleTy = SwiftTy->getAs(); - assert(TupleTy && "Tuple projection on non-tuple type!?"); - Identifier ElementName = TupleTy->getElement(P.getIndex()).getName(); + if (StructDecl *D = ContainingType.getStructOrBoundGenericStruct()) { + auto Iter = D->getStoredProperties().begin(); + std::advance(Iter, Index); + VarDecl *VD = *Iter; + os << VD->getBaseName(); + ContainingType = ContainingType.getFieldType(VD, M); + continue; + } + + if (auto TupleTy = ContainingType.getAs()) { + Identifier ElementName = TupleTy->getElement(Index).getName(); if (ElementName.empty()) - os << P.getIndex(); + os << Index; else os << ElementName; - break; + ContainingType = ContainingType.getTupleElementType(Index); + continue; } - default: - llvm_unreachable("Unexpected projection kind in SubPath!"); - } - ContainingType = P.getType(ContainingType, M); + + llvm_unreachable("Unexpected type in projection SubPath!"); } os << "'"; @@ -662,9 +724,11 @@ static void diagnoseExclusivityViolation(const ConflictingAccess &Violation, diagnose(Ctx, MainAccess.getAccessLoc().getSourceLoc(), DiagnosticID, PathDescription, AccessKindForMain); D.highlight(RangeForMain); - tryFixItWithCallToCollectionSwapAt(FirstAccess.getInstruction(), - SecondAccess.getInstruction(), - CallsToSwap, Ctx, D); + if (SecondAccess.getRecordKind() == RecordedAccessKind::BeginInstruction) { + tryFixItWithCallToCollectionSwapAt(FirstAccess.getInstruction(), + SecondAccess.getInstruction(), + CallsToSwap, Ctx, D); + } } else { auto DiagnosticID = (Ctx.LangOpts.isSwiftVersion3() ? diag::exclusivity_access_required_unknown_decl_swift3 : @@ -784,8 +848,14 @@ static bool isCallToStandardLibrarySwap(ApplyInst *AI, ASTContext &Ctx) { return FD == Ctx.getSwap(nullptr); } -static SILInstruction *getSingleAddressProjectionUser(SILInstruction *I) { +/// If the instruction is a field or tuple projection and it has a single +/// user return a pair of the single user and the projection index. +/// Otherwise, return a pair with the component nullptr and the second +/// unspecified. +static std::pair +getSingleAddressProjectionUser(SILInstruction *I) { SILInstruction *SingleUser = nullptr; + unsigned ProjectionIndex = 0; for (Operand *Use : I->getUses()) { SILInstruction *User = Use->getUser(); @@ -794,28 +864,43 @@ static SILInstruction *getSingleAddressProjectionUser(SILInstruction *I) { // We have more than a single user so bail. if (SingleUser) - return nullptr; + return std::make_pair(nullptr, 0); switch (User->getKind()) { case ValueKind::StructElementAddrInst: + ProjectionIndex = cast(User)->getFieldNo(); + SingleUser = User; + break; case ValueKind::TupleElementAddrInst: + ProjectionIndex = cast(User)->getFieldNo(); SingleUser = User; break; default: - return nullptr; + return std::make_pair(nullptr, 0); } } - return SingleUser; + return std::make_pair(SingleUser, ProjectionIndex); } -static ProjectionPath findSubPathAccessed(BeginAccessInst *BAI) { - ProjectionPath SubPath(BAI->getType(), BAI->getType()); +/// Returns an IndexTrieNode that represents the single subpath accessed from +/// BAI or the root if no such node exists. +static const IndexTrieNode *findSubPathAccessed(BeginAccessInst *BAI, + IndexTrieNode *Root) { + IndexTrieNode *SubPath = Root; + // For each single-user projection of BAI, construct or get a node + // from the trie representing the index of the field or tuple element + // accessed by that projection. SILInstruction *Iter = BAI; + while (true) { + std::pair ProjectionUser = + getSingleAddressProjectionUser(Iter); + if (!ProjectionUser.first) + break; - while ((Iter = getSingleAddressProjectionUser(Iter))) { - SubPath.push_back(Projection(Iter)); + SubPath = SubPath->getChild(ProjectionUser.second); + Iter = ProjectionUser.first; } return SubPath; @@ -826,14 +911,116 @@ static ProjectionPath findSubPathAccessed(BeginAccessInst *BAI) { /// with. Otherwise, returns None. Optional shouldReportAccess(const AccessInfo &Info, swift::SILAccessKind Kind, - const ProjectionPath &SubPath) { + const IndexTrieNode *SubPath) { if (Info.alreadyHadConflict()) return None; return Info.conflictsWithAccess(Kind, SubPath); } -static void checkStaticExclusivity(SILFunction &Fn, PostOrderFunctionInfo *PO) { +/// Use the summary analysis to check whether a call to the given +/// function would conflict with any in progress accesses. The starting +/// index indicates what index into the the callee's parameters the +/// arguments array starts at -- this is useful for partial_apply functions, +/// which pass only a suffix of the callee's arguments at the apply site. +static void checkForViolationWithCall( + const StorageMap &Accesses, SILFunction *Callee, unsigned StartingAtIndex, + OperandValueArrayRef Arguments, AccessSummaryAnalysis *ASA, + llvm::SmallVectorImpl &ConflictingAccesses) { + const AccessSummaryAnalysis::FunctionSummary &FS = + ASA->getOrCreateSummary(Callee); + + // For each argument in the suffix of the callee arguments being passed + // at this call site, determine whether the arguments will be accessed + // in a way that conflicts with any currently in progress accesses. + // If so, diagnose. + for (unsigned ArgumentIndex : indices(Arguments)) { + unsigned CalleeIndex = StartingAtIndex + ArgumentIndex; + + const AccessSummaryAnalysis::ArgumentSummary &AS = + FS.getAccessForArgument(CalleeIndex); + Optional Kind = AS.getAccessKind(); + if (!Kind) + continue; + + SILValue Argument = Arguments[ArgumentIndex]; + assert(Argument->getType().isAddress()); + + const AccessedStorage &Storage = findAccessedStorage(Argument); + auto AccessIt = Accesses.find(Storage); + if (AccessIt == Accesses.end()) + continue; + const AccessInfo &Info = AccessIt->getSecond(); + + // TODO: For now, treat a summarized access as an access to the whole + // address. Once the summary analysis is sensitive to stored properties, + // this should be updated look at the subpaths from the summary. + const IndexTrieNode *SubPath = ASA->getSubPathTrieRoot(); + if (auto Conflict = shouldReportAccess(Info, *Kind, SubPath)) { + SILLocation AccessLoc = AS.getAccessLoc(); + const auto &SecondAccess = RecordedAccess(*Kind, AccessLoc, SubPath); + ConflictingAccesses.emplace_back(Storage, *Conflict, SecondAccess); + } + } +} + +/// Look through a value passed as a function argument to determine whether +/// it is a partial_apply. +static PartialApplyInst *lookThroughForPartialApply(SILValue V) { + while (true) { + if (auto CFI = dyn_cast(V)) { + V = CFI->getOperand(); + continue; + } + + if (auto *PAI = dyn_cast(V)) + return PAI; + + return nullptr; + } +} + +/// Checks whether any of the arguments to the apply are closures and diagnoses +/// if any of the @inout_aliasable captures passed to those closures have +/// in-progress accesses that would conflict with any access the summary +/// says the closure would perform. +// +/// TODO: We currently fail to statically diagnose non-escaping closures pased +/// via @block_storage convention. To enforce this case, we should statically +/// recognize when the apply takes a block argument that has been initialized to +/// a non-escaping closure. +static void checkForViolationsInNoEscapeClosures( + const StorageMap &Accesses, FullApplySite FAS, AccessSummaryAnalysis *ASA, + llvm::SmallVectorImpl &ConflictingAccesses) { + + SILFunction *Callee = FAS.getCalleeFunction(); + if (Callee && !Callee->empty()) { + // Check for violation with directly called closure + checkForViolationWithCall(Accesses, Callee, 0, FAS.getArguments(), ASA, + ConflictingAccesses); + } + + // Check for violation with closures passed as arguments + for (SILValue Argument : FAS.getArguments()) { + auto *PAI = lookThroughForPartialApply(Argument); + if (!PAI) + continue; + + SILFunction *Closure = PAI->getCalleeFunction(); + if (!Closure || Closure->empty()) + continue; + + // Check the closure's captures, which are a suffix of the closure's + // parameters. + unsigned StartIndex = + Closure->getArguments().size() - PAI->getNumCallArguments(); + checkForViolationWithCall(Accesses, Closure, StartIndex, + PAI->getArguments(), ASA, ConflictingAccesses); + } +} + +static void checkStaticExclusivity(SILFunction &Fn, PostOrderFunctionInfo *PO, + AccessSummaryAnalysis *ASA) { // The implementation relies on the following SIL invariants: // - All incoming edges to a block must have the same in-progress // accesses. This enables the analysis to not perform a data flow merge @@ -899,7 +1086,8 @@ static void checkStaticExclusivity(SILFunction &Fn, PostOrderFunctionInfo *PO) { SILAccessKind Kind = BAI->getAccessKind(); const AccessedStorage &Storage = findAccessedStorage(BAI->getSource()); AccessInfo &Info = Accesses[Storage]; - ProjectionPath SubPath = findSubPathAccessed(BAI); + const IndexTrieNode *SubPath = + findSubPathAccessed(BAI, ASA->getSubPathTrieRoot()); if (auto Conflict = shouldReportAccess(Info, Kind, SubPath)) { ConflictingAccesses.emplace_back(Storage, *Conflict, RecordedAccess(BAI, SubPath)); @@ -914,7 +1102,8 @@ static void checkStaticExclusivity(SILFunction &Fn, PostOrderFunctionInfo *PO) { AccessInfo &Info = It->getSecond(); BeginAccessInst *BAI = EAI->getBeginAccess(); - const ProjectionPath &SubPath = findSubPathAccessed(BAI); + const IndexTrieNode *SubPath = + findSubPathAccessed(BAI, ASA->getSubPathTrieRoot()); Info.endAccess(EAI, SubPath); // If the storage location has no more in-progress accesses, remove @@ -928,8 +1117,17 @@ static void checkStaticExclusivity(SILFunction &Fn, PostOrderFunctionInfo *PO) { // Record calls to swap() for potential Fix-Its. if (isCallToStandardLibrarySwap(AI, Fn.getASTContext())) CallsToSwap.push_back(AI); + else + checkForViolationsInNoEscapeClosures(Accesses, AI, ASA, + ConflictingAccesses); + continue; } + if (auto *TAI = dyn_cast(&I)) { + checkForViolationsInNoEscapeClosures(Accesses, TAI, ASA, + ConflictingAccesses); + continue; + } // Sanity check to make sure entries are properly removed. assert((!isa(&I) || Accesses.size() == 0) && "Entries were not properly removed?!"); @@ -958,7 +1156,8 @@ private: return; PostOrderFunctionInfo *PO = getAnalysis()->get(Fn); - checkStaticExclusivity(*Fn, PO); + auto *ASA = getAnalysis(); + checkStaticExclusivity(*Fn, PO, ASA); } }; diff --git a/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp b/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp index 9233d705088..e5f8d102167 100644 --- a/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp +++ b/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp @@ -618,13 +618,16 @@ public: } /// constructor. - ReleaseBlockState(bool IsExit, unsigned size, bool MultiIteration) { + /// + /// If \p InitOptimistic is true, the block in-bits are initialized to 1 + /// which enables optimistic data flow evaluation. + ReleaseBlockState(bool InitOptimistic, unsigned size) { // backward data flow. // Initialize to true if we are running optimistic data flow, i.e. // MultiIteration is true. - BBSetIn.resize(size, MultiIteration); + BBSetIn.resize(size, InitOptimistic); BBSetOut.resize(size, false); - BBMaxSet.resize(size, !IsExit && MultiIteration); + BBMaxSet.resize(size, InitOptimistic); // Genset and Killset are initially empty. BBGenSet.resize(size, false); @@ -735,6 +738,17 @@ bool ReleaseCodeMotionContext::requireIteration() { } void ReleaseCodeMotionContext::initializeCodeMotionDataFlow() { + // All blocks which are initialized with 1-bits. These are all blocks which + // eventually reach the function exit (return, throw), excluding the + // function exit blocks themselves. + // Optimistic initialization enables moving releases across loops. On the + // other hand, blocks, which never reach the function exit, e.g. infinite + // loop blocks, must be excluded. Otherwise we would end up inserting + // completely unrelated release instructions in such blocks. + llvm::SmallPtrSet BlocksInitOptimistically; + + llvm::SmallVector Worklist; + // Find all the RC roots in the function. for (auto &BB : *F) { for (auto &II : BB) { @@ -750,13 +764,25 @@ void ReleaseCodeMotionContext::initializeCodeMotionDataFlow() { RCRootIndex[Root] = RCRootVault.size(); RCRootVault.insert(Root); } + if (MultiIteration && BB.getTerminator()->isFunctionExiting()) + Worklist.push_back(&BB); + } + + // Find all blocks from which there is a path to the function exit. + // Note: the Worklist is empty if we are not in MultiIteration mode. + while (!Worklist.empty()) { + SILBasicBlock *BB = Worklist.pop_back_val(); + for (SILBasicBlock *Pred : BB->getPredecessorBlocks()) { + if (BlocksInitOptimistically.insert(Pred).second) + Worklist.push_back(Pred); + } } // Initialize all the data flow bit vector for all basic blocks. for (auto &BB : *F) { BlockStates[&BB] = new (BPA.Allocate()) - ReleaseBlockState(BB.getTerminator()->isFunctionExiting(), - RCRootVault.size(), MultiIteration); + ReleaseBlockState(BlocksInitOptimistically.count(&BB) != 0, + RCRootVault.size()); } } @@ -1038,17 +1064,22 @@ public: return; DEBUG(llvm::dbgs() << "*** ARCCM on function: " << F->getName() << " ***\n"); + + PostOrderAnalysis *POA = PM->getAnalysis(); + // Split all critical edges. // // TODO: maybe we can do this lazily or maybe we should disallow SIL passes // to create critical edges. bool EdgeChanged = splitAllCriticalEdges(*F, false, nullptr, nullptr); + if (EdgeChanged) + POA->invalidateFunction(F); - llvm::SpecificBumpPtrAllocator BPA; - auto *PO = PM->getAnalysis()->get(F); + auto *PO = POA->get(F); auto *AA = PM->getAnalysis(); auto *RCFI = PM->getAnalysis()->get(F); + llvm::SpecificBumpPtrAllocator BPA; bool InstChanged = false; if (Kind == Release) { // TODO: we should consider Throw block as well, or better we should diff --git a/lib/SILOptimizer/Transforms/ArrayElementValuePropagation.cpp b/lib/SILOptimizer/Transforms/ArrayElementValuePropagation.cpp index a175954e920..522d673e5ca 100644 --- a/lib/SILOptimizer/Transforms/ArrayElementValuePropagation.cpp +++ b/lib/SILOptimizer/Transforms/ArrayElementValuePropagation.cpp @@ -320,7 +320,14 @@ public: for (const ArrayAllocation::AppendContentOfReplacement &Repl : Repls) { ArraySemanticsCall AppendContentsOf(Repl.AppendContentOfCall); assert(AppendContentsOf && "Must be AppendContentsOf call"); - + + NominalTypeDecl *AppendSelfArray = AppendContentsOf.getSelf()->getType(). + getSwiftRValueType()->getAnyNominal(); + + // In case if it's not an Array, but e.g. an ContiguousArray + if (AppendSelfArray != Ctx.getArrayDecl()) + continue; + SILType ArrayType = Repl.Array->getType(); auto *NTD = ArrayType.getSwiftRValueType()->getAnyNominal(); SubstitutionMap ArraySubMap = ArrayType.getSwiftRValueType() diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 54cdfabb525..efba8dda727 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -1227,19 +1227,15 @@ namespace { Expr *coerceToType(Expr *expr, Type toType, ConstraintLocatorBuilder locator, Optional typeFromPattern = None); - - using LevelTy = llvm::PointerEmbeddedInt; - + /// \brief Coerce the given expression (which is the argument to a call) to /// the given parameter type. /// /// This operation cannot fail. /// /// \param arg The argument expression. - /// \param paramType The parameter type. - /// \param applyOrLevel For function applications, the ApplyExpr that forms - /// the call. Otherwise, a specific level describing which parameter level - /// we're applying. + /// \param funcType The function type. + /// \param apply The ApplyExpr that forms the call. /// \param argLabels The argument labels provided for the call. /// \param hasTrailingClosure Whether the last argument is a trailing /// closure. @@ -1247,8 +1243,8 @@ namespace { /// /// \returns the coerced expression, which will have type \c ToType. Expr * - coerceCallArguments(Expr *arg, Type paramType, - llvm::PointerUnion applyOrLevel, + coerceCallArguments(Expr *arg, AnyFunctionType *funcType, + ApplyExpr *apply, ArrayRef argLabels, bool hasTrailingClosure, ConstraintLocatorBuilder locator); @@ -1406,10 +1402,9 @@ namespace { } // Coerce the index argument. - index = coerceCallArguments( - index, indexTy, LevelTy(1), argLabels, - hasTrailingClosure, - locator.withPathElement(ConstraintLocator::SubscriptIndex)); + index = coerceToType(index, indexTy, + locator.withPathElement( + ConstraintLocator::SubscriptIndex)); if (!index) return nullptr; @@ -4076,7 +4071,8 @@ namespace { baseTy && !baseTy->hasUnresolvedType() && !baseTy->isEqual(leafTy)) { - assert(leafTy->getAnyOptionalObjectType()->isEqual(baseTy)); + assert(leafTy->getAnyOptionalObjectType() + ->isEqual(baseTy->getLValueOrInOutObjectType())); auto component = KeyPathExpr::Component::forOptionalWrap(leafTy); resolvedComponents.push_back(component); baseTy = leafTy; @@ -4751,20 +4747,17 @@ Expr *ExprRewriter::coerceTupleToTuple(Expr *expr, TupleType *fromTuple, // Create the tuple shuffle. ArrayRef mapping = tc.Context.AllocateCopy(sources); auto callerDefaultArgsCopy = tc.Context.AllocateCopy(callerDefaultArgs); - auto shuffle = + return cs.cacheType(new (tc.Context) TupleShuffleExpr( expr, mapping, TupleShuffleExpr::SourceIsTuple, callee, tc.Context.AllocateCopy(variadicArgs), + arrayType, callerDefaultArgsCopy, toSugarType)); - shuffle->setVarargsArrayType(arrayType); - return shuffle; } - - Expr *ExprRewriter::coerceScalarToTuple(Expr *expr, TupleType *toTuple, int toScalarIdx, ConstraintLocatorBuilder locator) { @@ -4849,13 +4842,13 @@ Expr *ExprRewriter::coerceScalarToTuple(Expr *expr, TupleType *toTuple, Type destSugarTy = hasInit? toTuple : TupleType::get(sugarFields, tc.Context); - - return cs.cacheType( - new (tc.Context) TupleShuffleExpr(expr, + + return cs.cacheType(new (tc.Context) TupleShuffleExpr(expr, tc.Context.AllocateCopy(elements), TupleShuffleExpr::SourceIsScalar, callee, tc.Context.AllocateCopy(variadicArgs), + arrayType, tc.Context.AllocateCopy(callerDefaultArgs), destSugarTy)); } @@ -5140,24 +5133,13 @@ static bool isReferenceToMetatypeMember(ConstraintSystem &cs, Expr *expr) { return false; } -static unsigned computeCallLevel( - ConstraintSystem &cs, ConcreteDeclRef callee, - llvm::PointerUnion applyOrLevel) { - using LevelTy = ExprRewriter::LevelTy; - - if (applyOrLevel.is()) { - // Level specified by caller. - return applyOrLevel.get(); - } - +static unsigned computeCallLevel(ConstraintSystem &cs, ConcreteDeclRef callee, + ApplyExpr *apply) { // If we do not have a callee, return a level of 0. if (!callee) { return 0; } - // Determine the level based on the application itself. - auto *apply = applyOrLevel.get(); - // Only calls to members of types can have level > 0. auto calleeDecl = callee.getDecl(); if (!calleeDecl->getDeclContext()->isTypeContext()) { @@ -5184,12 +5166,13 @@ static unsigned computeCallLevel( } Expr *ExprRewriter::coerceCallArguments( - Expr *arg, Type paramType, - llvm::PointerUnion applyOrLevel, + Expr *arg, AnyFunctionType *funcType, + ApplyExpr *apply, ArrayRef argLabels, bool hasTrailingClosure, ConstraintLocatorBuilder locator) { - + + auto paramType = funcType->getInput(); // Local function to produce a locator to refer to the ith element of the // argument tuple. auto getArgLocator = [&](unsigned argIdx, unsigned paramIdx) @@ -5221,6 +5204,9 @@ Expr *ExprRewriter::coerceCallArguments( } } } + + // Rebuild the function type. + funcType = FunctionType::get(paramType, funcType->getResult()); } bool allParamsMatch = cs.getType(arg)->isEqual(paramType); @@ -5230,10 +5216,12 @@ Expr *ExprRewriter::coerceCallArguments( findCalleeDeclRef(cs, solution, cs.getConstraintLocator(locator)); // Determine the level, - unsigned level = computeCallLevel(cs, callee, applyOrLevel); + unsigned level = computeCallLevel(cs, callee, apply); // Determine the parameter bindings. - auto params = decomposeParamType(paramType, callee.getDecl(), level); + auto params = funcType->getParams(); + SmallVector defaultMap; + computeDefaultMap(paramType, callee.getDecl(), level, defaultMap); auto args = decomposeArgType(cs.getType(arg), argLabels); // Quickly test if any further fix-ups for the argument types are necessary. @@ -5247,7 +5235,7 @@ Expr *ExprRewriter::coerceCallArguments( for (size_t i = 0; i < params.size(); i++) { if (auto dotExpr = dyn_cast(argElts[i])) { - auto paramTy = params[i].Ty->getLValueOrInOutObjectType(); + auto paramTy = params[i].getType()->getLValueOrInOutObjectType(); auto argTy = cs.getType(dotExpr)->getLValueOrInOutObjectType(); if (!paramTy->isEqual(argTy)) { allParamsMatch = false; @@ -5262,9 +5250,9 @@ Expr *ExprRewriter::coerceCallArguments( return arg; MatchCallArgumentListener listener; - SmallVector parameterBindings; bool failed = constraints::matchCallArguments(args, params, + defaultMap, hasTrailingClosure, /*allowFixes=*/false, listener, parameterBindings); @@ -5322,11 +5310,11 @@ Expr *ExprRewriter::coerceCallArguments( return nullptr; // Record this parameter. - auto paramBaseType = param.Ty; + auto paramBaseType = param.getType(); assert(sliceType.isNull() && "Multiple variadic parameters?"); sliceType = tc.getArraySliceType(arg->getLoc(), paramBaseType); toSugarFields.push_back( - TupleTypeElt(sliceType, param.Label, param.parameterFlags)); + TupleTypeElt(sliceType, param.getLabel(), param.getParameterFlags())); sources.push_back(TupleShuffleExpr::Variadic); // Convert the arguments. @@ -5370,10 +5358,10 @@ Expr *ExprRewriter::coerceCallArguments( toSugarFields.push_back(TupleTypeElt( param.isVariadic() ? tc.getArraySliceType(arg->getLoc(), - param.Ty) - : param.Ty, - param.Label, - param.parameterFlags)); + param.getType()) + : param.getType(), + param.getLabel(), + param.getParameterFlags())); if (defArg) { callerDefaultArgs.push_back(defArg); @@ -5395,12 +5383,12 @@ Expr *ExprRewriter::coerceCallArguments( sources.push_back(argIdx); // If the types exactly match, this is easy. - auto paramType = param.Ty; + auto paramType = param.getType(); if (argType->isEqual(paramType)) { toSugarFields.push_back( - TupleTypeElt(argType, getArgLabel(argIdx), param.parameterFlags)); + TupleTypeElt(argType, getArgLabel(argIdx), param.getParameterFlags())); fromTupleExprFields[argIdx] = - TupleTypeElt(paramType, getArgLabel(argIdx), param.parameterFlags); + TupleTypeElt(paramType, getArgLabel(argIdx), param.getParameterFlags()); fromTupleExpr[argIdx] = arg; continue; } @@ -5414,9 +5402,9 @@ Expr *ExprRewriter::coerceCallArguments( // Add the converted argument. fromTupleExpr[argIdx] = convertedArg; fromTupleExprFields[argIdx] = TupleTypeElt( - cs.getType(convertedArg), getArgLabel(argIdx), param.parameterFlags); + cs.getType(convertedArg), getArgLabel(argIdx), param.getParameterFlags()); toSugarFields.push_back( - TupleTypeElt(argType, param.Label, param.parameterFlags)); + TupleTypeElt(argType, param.getLabel(), param.getParameterFlags())); } // Compute a new 'arg', from the bits we have. We have three cases: the @@ -5483,16 +5471,15 @@ Expr *ExprRewriter::coerceCallArguments( // Create the tuple shuffle. ArrayRef mapping = tc.Context.AllocateCopy(sources); auto callerDefaultArgsCopy = tc.Context.AllocateCopy(callerDefaultArgs); - auto *shuffle = + return cs.cacheType(new (tc.Context) TupleShuffleExpr( arg, mapping, isSourceScalar, callee, tc.Context.AllocateCopy(variadicArgs), + sliceType, callerDefaultArgsCopy, paramType)); - shuffle->setVarargsArrayType(sliceType); - return shuffle; } static ClosureExpr *getClosureLiteralExpr(Expr *expr) { @@ -6713,7 +6700,7 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, SmallVector argLabelsScratch; auto fnType = cs.getType(fn)->getAs(); - arg = coerceCallArguments(arg, fnType->getInput(), + arg = coerceCallArguments(arg, fnType, apply, apply->getArgumentLabels(argLabelsScratch), hasTrailingClosure, @@ -6892,7 +6879,7 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, SmallVector argLabelsScratch; if (auto fnType = cs.getType(fn)->getAs()) { auto origArg = apply->getArg(); - Expr *arg = coerceCallArguments(origArg, fnType->getInput(), + Expr *arg = coerceCallArguments(origArg, fnType, apply, apply->getArgumentLabels(argLabelsScratch), hasTrailingClosure, @@ -7513,6 +7500,10 @@ Expr *ConstraintSystem::applySolution(Solution &solution, Expr *expr, return nullptr; } + // Mark any normal conformances used in this solution as "used". + for (auto &e : solution.Conformances) + TC.markConformanceUsed(e.second, DC); + ExprRewriter rewriter(*this, solution, suppressDiagnostics, skipClosures); ExprWalker walker(rewriter); diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp index 6f9cc06c03a..6fa592ff314 100644 --- a/lib/Sema/CSDiag.cpp +++ b/lib/Sema/CSDiag.cpp @@ -387,9 +387,14 @@ static bool diagnoseAmbiguity(ConstraintSystem &cs, // Find the locators which have the largest numbers of distinct overloads. Optional bestOverload; - unsigned maxDistinctOverloads = 0; - unsigned maxDepth = 0; - unsigned minIndex = std::numeric_limits::max(); + // Overloads are scored by lexicographical comparison of (# of distinct + // overloads, depth, *reverse* of the index). N.B. - cannot be used for the + // reversing: the score version of index == 0 should be > than that of 1, but + // -0 == 0 < UINT_MAX == -1, whereas ~0 == UINT_MAX > UINT_MAX - 1 == ~1. + auto score = [](unsigned distinctOverloads, unsigned depth, unsigned index) { + return std::make_tuple(distinctOverloads, depth, ~index); + }; + auto bestScore = score(0, 0, std::numeric_limits::max()); // Get a map of expressions to their depths and post-order traversal indices. // Heuristically, all other things being equal, we should complain about the @@ -428,27 +433,10 @@ static bool diagnoseAmbiguity(ConstraintSystem &cs, // If we have more distinct overload choices for this locator than for // prior locators, just keep this locator. - - bool better = false; - if (bestOverload) { - if (distinctOverloads > maxDistinctOverloads) { - better = true; - } else if (distinctOverloads == maxDistinctOverloads) { - if (depth > maxDepth) { - better = true; - } else if (depth == maxDepth) { - if (index < minIndex) { - better = true; - } - } - } - } - - if (!bestOverload || better) { + auto thisScore = score(distinctOverloads, depth, index); + if (thisScore > bestScore) { + bestScore = thisScore; bestOverload = i; - maxDistinctOverloads = distinctOverloads; - maxDepth = depth; - minIndex = index; continue; } @@ -1035,9 +1023,9 @@ namespace { /// resultant set. ClosenessResultTy evaluateCloseness(UncurriedCandidate candidate, - ArrayRef actualArgs); + ArrayRef actualArgs); - void filterListArgs(ArrayRef actualArgs); + void filterListArgs(ArrayRef actualArgs); void filterList(Type actualArgsType, ArrayRef argLabels) { return filterListArgs(decomposeArgType(actualArgsType, argLabels)); } @@ -1231,13 +1219,15 @@ static bool findGenericSubstitutions(DeclContext *dc, Type paramType, /// information about that failure. CalleeCandidateInfo::ClosenessResultTy CalleeCandidateInfo::evaluateCloseness(UncurriedCandidate candidate, - ArrayRef actualArgs) { + ArrayRef actualArgs) { auto *dc = candidate.getDecl() ? candidate.getDecl()->getInnermostDeclContext() : nullptr; - auto candArgs = decomposeParamType(candidate.getArgumentType(), - candidate.getDecl(), - candidate.level); + + auto candArgs = candidate.getUncurriedFunctionType()->getParams(); + SmallVector candDefaultMap; + computeDefaultMap(candidate.getArgumentType(), candidate.getDecl(), + candidate.level, candDefaultMap); struct OurListener : public MatchCallArgumentListener { CandidateCloseness result = CC_ExactMatch; @@ -1267,7 +1257,9 @@ CalleeCandidateInfo::evaluateCloseness(UncurriedCandidate candidate, // shape) to the specified candidates parameters. This ignores the concrete // types of the arguments, looking only at the argument labels etc. SmallVector paramBindings; - if (matchCallArguments(actualArgs, candArgs, hasTrailingClosure, + if (matchCallArguments(actualArgs, candArgs, + candDefaultMap, + hasTrailingClosure, /*allowFixes:*/ true, listener, paramBindings)) // On error, get our closeness from whatever problem the listener saw. @@ -1300,25 +1292,25 @@ CalleeCandidateInfo::evaluateCloseness(UncurriedCandidate candidate, CalleeCandidateInfo::FailedArgumentInfo failureInfo; // Local function which extracts type from the parameter container. - auto getType = [](const CallArgParam ¶m) -> Type { + auto getParamResultType = [](const AnyFunctionType::Param ¶m) -> Type { // If parameter is marked as @autoclosure, we are // only interested in it's resulting type. if (param.isAutoClosure()) { - if (auto fnType = param.Ty->getAs()) + if (auto fnType = param.getType()->getAs()) return fnType->getResult(); } - return param.Ty; + return param.getType(); }; - + for (unsigned i = 0, e = paramBindings.size(); i != e; ++i) { // Bindings specify the arguments that source the parameter. The only case // this returns a non-singular value is when there are varargs in play. auto &bindings = paramBindings[i]; - auto paramType = getType(candArgs[i]); + auto paramType = getParamResultType(candArgs[i]); for (auto argNo : bindings) { - auto argType = getType(actualArgs[argNo]); + auto argType = getParamResultType(actualArgs[argNo]); auto rArgType = argType->getRValueType(); // If the argument has an unresolved type, then we're not actually @@ -1437,8 +1429,8 @@ CalleeCandidateInfo::evaluateCloseness(UncurriedCandidate candidate, // Check to see if the first argument expects an inout argument, but is not // an lvalue. - Type firstArg = actualArgs[0].Ty; - if (candArgs[0].Ty->is() && !(firstArg->hasLValueType() || firstArg->is())) + Type firstArg = actualArgs[0].getType(); + if (candArgs[0].getType()->is() && !(firstArg->hasLValueType() || firstArg->is())) return { CC_NonLValueInOut, {}}; // If we have exactly one argument mismatching, classify it specially, so that @@ -1536,7 +1528,7 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn, if (auto declRefExpr = dyn_cast(fn)) { auto decl = declRefExpr->getDecl(); candidates.push_back({ decl, getCalleeLevel(decl) }); - declName = decl->getNameStr().str(); + declName = decl->getBaseName().userFacingName(); return; } @@ -1557,7 +1549,7 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn, } if (!candidates.empty()) - declName = candidates[0].getDecl()->getNameStr().str(); + declName = candidates[0].getDecl()->getBaseName().userFacingName(); return; } @@ -1690,7 +1682,7 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn, if (candidates.empty()) continue; if (declName.empty()) - declName = candidates[0].getDecl()->getNameStr().str(); + declName = candidates[0].getDecl()->getBaseName().userFacingName(); return; } @@ -1701,7 +1693,7 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn, /// After the candidate list is formed, it can be filtered down to discard /// obviously mismatching candidates and compute a "closeness" for the /// resultant set. -void CalleeCandidateInfo::filterListArgs(ArrayRef actualArgs) { +void CalleeCandidateInfo::filterListArgs(ArrayRef actualArgs) { // Now that we have the candidate list, figure out what the best matches from // the candidate list are, and remove all the ones that aren't at that level. filterList([&](UncurriedCandidate candidate) -> ClosenessResultTy { @@ -1743,23 +1735,19 @@ void CalleeCandidateInfo::filterContextualMemberList(Expr *argExpr) { if (isa(argExpr)) argType = LValueType::get(argType); - CallArgParam param; - param.Ty = argType; - return filterListArgs(param); + return filterListArgs(AnyFunctionType::Param({argType, Identifier(), {}})); } // If we have a tuple expression, form a tuple type. - SmallVector ArgElts; + SmallVector ArgElts; for (unsigned i = 0, e = argTuple->getNumElements(); i != e; ++i) { // If the argument has an & specified, then we expect an lvalue. Type argType = URT; if (isa(argTuple->getElement(i))) argType = LValueType::get(argType); - CallArgParam param; - param.Ty = argType; - param.Label = argTuple->getElementName(i); - ArgElts.push_back(param); + ArgElts.push_back(AnyFunctionType::Param(argType, + argTuple->getElementName(i), {})); } return filterListArgs(ArgElts); @@ -1825,7 +1813,7 @@ CalleeCandidateInfo::CalleeCandidateInfo(Type baseType, } if (!candidates.empty()) - declName = candidates[0].getDecl()->getNameStr().str(); + declName = candidates[0].getDecl()->getBaseName().userFacingName(); } @@ -2065,12 +2053,17 @@ public: /// Attempt to produce a diagnostic for a mismatch between an expression's /// type and its assumed contextual type. - bool diagnoseContextualConversionError(); + bool diagnoseContextualConversionError(Expr *expr, Type contextualType); /// For an expression being type checked with a CTP_CalleeResult contextual /// type, try to diagnose a problem. bool diagnoseCalleeResultContextualConversionError(); + /// Attempt to produce a diagnostic for a mismatch between a call's + /// type and its assumed contextual type. + bool diagnoseCallContextualConversionErrors(ApplyExpr *callEpxr, + Type contextualType); + private: /// Validate potential contextual type for type-checking one of the /// sub-expressions, usually correct/valid types are the ones which @@ -2157,6 +2150,11 @@ private: Optional)>> callback = None, bool includeInaccessibleMembers = true); + bool diagnoseTrailingClosureErrors(ApplyExpr *expr); + + bool diagnoseClosureExpr(ClosureExpr *closureExpr, Type contextualType, + std::function resultTypeProcessor); + bool visitExpr(Expr *E); bool visitIdentityExpr(IdentityExpr *E); bool visitTryExpr(TryExpr *E); @@ -3852,8 +3850,7 @@ static bool tryDiagnoseNonEscapingParameterToEscaping(Expr *expr, Type srcType, // Give a note and fixit InFlightDiagnostic note = CS->TC.diagnose( - paramDecl->getLoc(), srcFT->isAutoClosure() ? diag::noescape_autoclosure - : diag::noescape_parameter, + paramDecl->getLoc(), diag::noescape_parameter, paramDecl->getName()); if (!srcFT->isAutoClosure()) { @@ -3864,10 +3861,10 @@ static bool tryDiagnoseNonEscapingParameterToEscaping(Expr *expr, Type srcType, return true; } -bool FailureDiagnosis::diagnoseContextualConversionError() { +bool FailureDiagnosis::diagnoseContextualConversionError(Expr *expr, + Type contextualType) { // If the constraint system has a contextual type, then we can test to see if // this is the problem that prevents us from solving the system. - Type contextualType = CS->getContextualType(); if (!contextualType) { // This contextual conversion constraint doesn't install an actual type. if (CS->getContextualTypePurpose() == CTP_CalleeResult) @@ -4482,23 +4479,26 @@ typeCheckArgumentChildIndependently(Expr *argExpr, Type argType, // care about the actual types though, so we can just use 'void' for them. // FIXME: This doesn't need to be limited to tuple types. if (argType && argType->is()) { - // Decompose the parameter type, including information about default - // arguments. - SmallVector params = - decomposeParamType( - argType, - candidates.empty() ? nullptr : candidates[0].getDecl(), - candidates.empty() ? 0 : candidates[0].level); + // Decompose the parameter type. + SmallVector params; + AnyFunctionType::decomposeInput(argType, params); + + // If we have a candidate function around, compute the position of its + // default arguments. + SmallVector defaultMap; + if (candidates.empty()) { + defaultMap.assign(params.size(), false); + } else { + computeDefaultMap(argType, candidates[0].getDecl(), + candidates[0].level, defaultMap); + } // Form a set of call arguments, using a dummy type (Void), because the // argument/parameter matching code doesn't need it. auto voidTy = CS->getASTContext().TheEmptyTupleType; - SmallVector args; + SmallVector args; for (unsigned i = 0, e = TE->getNumElements(); i != e; ++i) { - CallArgParam arg; - arg.Ty = voidTy; - arg.Label = TE->getElementName(i); - args.push_back(arg); + args.push_back(AnyFunctionType::Param(voidTy, TE->getElementName(i), {})); } /// Use a match call argument listener that allows relabeling. @@ -4509,7 +4509,8 @@ typeCheckArgumentChildIndependently(Expr *argExpr, Type argType, } listener; SmallVector paramBindings; - if (!matchCallArguments(args, params, callArgHasTrailingClosure(argExpr), + if (!matchCallArguments(args, params, defaultMap, + callArgHasTrailingClosure(argExpr), /*allowFixes=*/true, listener, paramBindings)) { SmallVector resultElts(TE->getNumElements(), nullptr); @@ -4521,7 +4522,7 @@ typeCheckArgumentChildIndependently(Expr *argExpr, Type argType, const auto ¶m = params[paramIdx]; // Determine the parameter type. - auto currentParamType = param.Ty; + auto currentParamType = param.getType(); if (currentParamType->is()) options |= TCC_AllowLValue; @@ -4698,16 +4699,39 @@ static bool diagnoseImplicitSelfErrors(Expr *fnExpr, Expr *argExpr, base); calleeInfo.filterList(argType, argLabels); - if (calleeInfo.closeness != CC_ExactMatch) + + auto diagnostic = diag::member_shadows_global_function_near_match; + switch (calleeInfo.closeness) { + case CC_Unavailable: + case CC_Inaccessible: + case CC_SelfMismatch: + case CC_ArgumentLabelMismatch: + case CC_ArgumentCountMismatch: + case CC_GeneralMismatch: return false; + case CC_NonLValueInOut: + case CC_OneArgumentNearMismatch: + case CC_OneArgumentMismatch: + case CC_OneGenericArgumentNearMismatch: + case CC_OneGenericArgumentMismatch: + case CC_ArgumentNearMismatch: + case CC_ArgumentMismatch: + case CC_GenericNonsubstitutableMismatch: + break; // Near match cases + + case CC_ExactMatch: + diagnostic = diag::member_shadows_global_function; + break; + } + auto choice = calleeInfo.candidates[0].getDecl(); auto baseKind = getBaseKind(base); auto baseName = getBaseName(choice->getDeclContext()); auto origCandidate = CCI[0].getDecl(); - TC.diagnose(UDE->getLoc(), diag::member_shadows_global_function, - UDE->getName(), origCandidate->getDescriptiveKind(), + TC.diagnose(UDE->getLoc(), diagnostic, UDE->getName(), + origCandidate->getDescriptiveKind(), origCandidate->getFullName(), choice->getDescriptiveKind(), choice->getFullName(), baseKind, baseName); @@ -4814,7 +4838,9 @@ diagnoseInstanceMethodAsCurriedMemberOnType(CalleeCandidateInfo &CCI, (decl->isInstanceMember() && candidate.level == 1)) continue; - auto params = decomposeParamType(argTy, decl, candidate.level); + auto params = candidate.getUncurriedFunctionType()->getParams(); + SmallVector defaultMap; + computeDefaultMap(argTy, decl, candidate.level, defaultMap); // If one of the candidates is an instance method with a single parameter // at the level 0, this might be viable situation for calling instance // method as curried member of type problem. @@ -4951,7 +4977,7 @@ static bool diagnoseTupleParameterMismatch(CalleeCandidateInfo &CCI, // Constructors/descructors and subscripts don't really have names. if (!(isa(decl) || isa(decl) || isa(decl))) { - name = decl->getName(); + name = decl->getBaseName().getIdentifier(); } TC.diagnose(argExpr->getLoc(), diag::single_tuple_parameter_mismatch, @@ -4993,7 +5019,9 @@ static bool diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI, auto argTy = candidate.getArgumentType(); if (!argTy) return false; - auto params = decomposeParamType(argTy, candidate.getDecl(), candidate.level); + auto params = candidate.getUncurriedFunctionType()->getParams(); + SmallVector defaultMap; + computeDefaultMap(argTy, candidate.getDecl(), candidate.level, defaultMap); auto args = decomposeArgType(CCI.CS->getType(argExpr), argLabels); // Check the case where a raw-representable type is constructed from an @@ -5009,10 +5037,10 @@ static bool diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI, if (params.size() == 1 && args.size() == 1 && candidate.getDecl() && isa(candidate.getDecl()) && candidate.level == 1) { - CallArgParam &arg = args[0]; + AnyFunctionType::Param &arg = args[0]; auto resTy = candidate.getResultType()->lookThroughAllAnyOptionalTypes(); auto rawTy = isRawRepresentable(resTy, CCI.CS); - if (rawTy && arg.Ty && resTy->isEqual(arg.Ty)) { + if (rawTy && arg.getType() && resTy->isEqual(arg.getType())) { auto getInnerExpr = [](Expr *E) -> Expr* { auto *parenE = dyn_cast(E); if (!parenE) @@ -5048,8 +5076,9 @@ static bool diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI, TypeChecker &TC; Expr *FnExpr; Expr *ArgExpr; - llvm::SmallVectorImpl &Parameters; - llvm::SmallVectorImpl &Arguments; + ArrayRef &Parameters; + SmallVectorImpl &DefaultMap; + SmallVectorImpl &Arguments; CalleeCandidateInfo CandidateInfo; @@ -5064,15 +5093,16 @@ static bool diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI, public: ArgumentDiagnostic(Expr *fnExpr, Expr *argExpr, - llvm::SmallVectorImpl ¶ms, - llvm::SmallVectorImpl &args, + ArrayRef ¶ms, + SmallVectorImpl &defaultMap, + SmallVectorImpl &args, CalleeCandidateInfo &CCI, bool isSubscript) : TC(CCI.CS->TC), FnExpr(fnExpr), ArgExpr(argExpr), - Parameters(params), Arguments(args), + Parameters(params), DefaultMap(defaultMap), Arguments(args), CandidateInfo(CCI), IsSubscript(isSubscript) {} void extraArgument(unsigned extraArgIdx) override { - auto name = Arguments[extraArgIdx].Label; + auto name = Arguments[extraArgIdx].getLabel(); Expr *arg = ArgExpr; auto tuple = dyn_cast(ArgExpr); @@ -5112,7 +5142,7 @@ static bool diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI, void missingArgument(unsigned missingParamIdx) override { auto ¶m = Parameters[missingParamIdx]; - Identifier name = param.Label; + Identifier name = param.getLabel(); // Search insertion index. unsigned argIdx = 0; @@ -5134,14 +5164,14 @@ static bool diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI, insertText << ", "; if (!name.empty()) insertText << name.str() << ": "; - Type Ty = param.Ty; + Type Ty = param.getType(); // Explode inout type. - if (auto IOT = param.Ty->getAs()) { + if (auto IOT = param.getType()->getAs()) { insertText << "&"; Ty = IOT->getObjectType(); } // @autoclosure; the type should be the result type. - if (auto FT = param.Ty->getAs()) + if (auto FT = param.getType()->getAs()) if (FT->isAutoClosure()) Ty = FT->getResult(); insertText << "<#" << Ty << "#>"; @@ -5241,7 +5271,7 @@ static bool diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI, auto tuple = cast(ArgExpr); TC.diagnose(tuple->getElement(paramIdx)->getStartLoc(), diag::missing_argument_labels, false, - Parameters[paramIdx].Label.str(), IsSubscript); + Parameters[paramIdx].getLabel().str(), IsSubscript); Diagnosed = true; } @@ -5310,7 +5340,7 @@ static bool diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI, // Use matchCallArguments to determine how close the argument list is (in // shape) to the specified candidates parameters. This ignores the // concrete types of the arguments, looking only at the argument labels. - matchCallArguments(Arguments, Parameters, + matchCallArguments(Arguments, Parameters, DefaultMap, CandidateInfo.hasTrailingClosure, /*allowFixes:*/ true, *this, Bindings); @@ -5318,7 +5348,7 @@ static bool diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI, } }; - return ArgumentDiagnostic(fnExpr, argExpr, params, args, CCI, + return ArgumentDiagnostic(fnExpr, argExpr, params, defaultMap, args, CCI, isa(fnExpr)) .diagnose(); } @@ -5381,15 +5411,17 @@ static bool diagnoseRawRepresentableMismatch(CalleeCandidateInfo &CCI, if (!decl) continue; - auto parameters = - decomposeParamType(candidate.getArgumentType(), decl, candidate.level); + auto parameters = candidate.getUncurriedFunctionType()->getParams(); + SmallVector defaultMap; + computeDefaultMap(candidate.getArgumentType(), decl, + candidate.level, defaultMap); if (parameters.size() != arguments.size()) continue; for (unsigned i = 0, n = parameters.size(); i != n; ++i) { - auto paramType = parameters[i].Ty; - auto argType = arguments[i].Ty; + auto paramType = parameters[i].getType(); + auto argType = arguments[i].getType(); for (auto kind : rawRepresentableProtocols) { // If trying to convert from raw type to raw representable, @@ -5492,7 +5524,7 @@ bool FailureDiagnosis::diagnoseParameterErrors(CalleeCandidateInfo &CCI, // It could be that the argument doesn't conform to an archetype. if (CCI.diagnoseGenericParameterErrors(badArgExpr)) return true; - + // Re-type-check the argument with the expected type of the candidate set. // This should produce a specific and tailored diagnostic saying that the // type mismatches with expectations. @@ -5851,13 +5883,17 @@ bool FailureDiagnosis::diagnoseArgumentGenericRequirements( return false; auto const &candidate = candidates.candidates[0]; - auto params = decomposeParamType(candidate.getArgumentType(), - candidate.getDecl(), candidate.level); + auto params = candidate.getUncurriedFunctionType()->getParams(); + SmallVector defaultMap; + computeDefaultMap(candidate.getArgumentType(), candidate.getDecl(), + candidate.level, defaultMap); + auto args = decomposeArgType(CS->getType(argExpr), argLabels); SmallVector bindings; MatchCallArgumentListener listener; - if (matchCallArguments(args, params, candidates.hasTrailingClosure, + if (matchCallArguments(args, params, defaultMap, + candidates.hasTrailingClosure, /*allowFixes=*/false, listener, bindings)) return false; @@ -5867,14 +5903,14 @@ bool FailureDiagnosis::diagnoseArgumentGenericRequirements( // requirements e.g. . for (unsigned i = 0, e = bindings.size(); i != e; ++i) { auto param = params[i]; - auto archetype = param.Ty->getAs(); + auto archetype = param.getType()->getAs(); if (!archetype) continue; // Bindings specify the arguments that source the parameter. The only case // this returns a non-singular value is when there are varargs in play. for (auto argNo : bindings[i]) { - auto argType = args[argNo].Ty->getLValueOrInOutObjectType(); + auto argType = args[argNo].getType()->getLValueOrInOutObjectType(); if (argType->is()) { diagnoseUnboundArchetype(archetype, fnExpr); @@ -5952,10 +5988,304 @@ static bool isCastToTypedPointer(ConstraintSystem *CS, const Expr *Fn, return true; } +static bool diagnoseClosureExplicitParameterMismatch( + ConstraintSystem *const CS, SourceLoc loc, + ArrayRef params, + ArrayRef args) { + // We are not trying to diagnose structural problems with top-level + // arguments here. + if (params.size() != args.size()) + return false; + + for (unsigned i = 0, n = params.size(); i != n; ++i) { + auto paramType = params[i].getType(); + auto argType = args[i].getType(); + + if (auto paramFnType = paramType->getAs()) { + if (auto argFnType = argType->getAs()) + return diagnoseClosureExplicitParameterMismatch( + CS, loc, paramFnType->getParams(), argFnType->getParams()); + } + + if (!paramType || !argType || isUnresolvedOrTypeVarType(paramType) || + isUnresolvedOrTypeVarType(argType)) + continue; + + if (!CS->TC.isConvertibleTo(argType, paramType, CS->DC)) { + CS->TC.diagnose(loc, diag::types_not_convertible, false, paramType, + argType); + return true; + } + } + + return false; +} + +bool FailureDiagnosis::diagnoseTrailingClosureErrors(ApplyExpr *callExpr) { + if (!callExpr->hasTrailingClosure()) + return false; + + auto *fnExpr = callExpr->getFn(); + auto *argExpr = callExpr->getArg(); + + ClosureExpr *closureExpr = nullptr; + if (auto *PE = dyn_cast(argExpr)) { + closureExpr = dyn_cast(PE->getSubExpr()); + } else { + return false; + } + + if (!closureExpr) + return false; + + class CallResultListener : public ExprTypeCheckListener { + Type expectedResultType; + + public: + explicit CallResultListener(Type resultType) + : expectedResultType(resultType) {} + + bool builtConstraints(ConstraintSystem &cs, Expr *expr) override { + if (!expectedResultType) + return false; + + auto resultType = cs.getType(expr); + auto *locator = cs.getConstraintLocator(expr); + + // Since we know that this is trailing closure, format of the + // type could be like this - ((Input) -> Result) -> ClosureResult + // which we can leverage to create specific conversion for + // result type of the call itself, this might help us gain + // some valuable contextual information. + if (auto *fnType = resultType->getAs()) { + cs.addConstraint(ConstraintKind::Conversion, fnType->getResult(), + expectedResultType, locator); + } else if (auto *typeVar = resultType->getAs()) { + auto tv = + cs.createTypeVariable(cs.getConstraintLocator(expr), + TVO_CanBindToLValue | TVO_CanBindToInOut | + TVO_PrefersSubtypeBinding); + + auto extInfo = FunctionType::ExtInfo().withThrows(); + auto fTy = FunctionType::get(ParenType::get(cs.getASTContext(), tv), + expectedResultType, extInfo); + + // Add a conversion constraint between the types. + cs.addConstraint(ConstraintKind::Conversion, typeVar, fTy, locator, + /*isFavored*/ true); + } + + return false; + } + }; + + SmallVector possibleTypes; + auto currentType = CS->getType(fnExpr); + + // If current type has type variables or unresolved types + // let's try to re-typecheck it to see if we can get some + // more information about what is going on. + if (currentType->hasTypeVariable() || currentType->hasUnresolvedType()) { + auto contextualType = CS->getContextualType(); + CallResultListener listener(contextualType); + CS->TC.getPossibleTypesOfExpressionWithoutApplying( + fnExpr, CS->DC, possibleTypes, FreeTypeVariableBinding::UnresolvedType, + &listener); + + // Looks like there is there a contextual mismatch + // related to function type, let's try to diagnose it. + if (possibleTypes.empty() && contextualType && + !contextualType->hasUnresolvedType()) + return diagnoseContextualConversionError(callExpr, contextualType); + } else { + possibleTypes.push_back(currentType); + } + + for (auto type : possibleTypes) { + auto *fnType = type->getAs(); + if (!fnType) + continue; + + auto paramType = fnType->getInput(); + switch (paramType->getKind()) { + case TypeKind::Tuple: { + auto tuple = paramType->getAs(); + if (tuple->getNumElements() != 1) + continue; + + paramType = tuple->getElement(0).getType(); + break; + } + + case TypeKind::Paren: + paramType = paramType->getWithoutParens(); + break; + + default: + return false; + } + + if (auto paramFnType = paramType->getAs()) { + auto closureType = CS->getType(closureExpr); + if (auto *argFnType = closureType->getAs()) { + auto *params = closureExpr->getParameters(); + auto loc = params ? params->getStartLoc() : closureExpr->getStartLoc(); + if (diagnoseClosureExplicitParameterMismatch( + CS, loc, argFnType->getParams(), paramFnType->getParams())) + return true; + } + } + + auto processor = [&](Type resultType, Type expectedResultType) -> bool { + if (resultType && expectedResultType) { + if (!resultType->isEqual(expectedResultType)) { + CS->TC.diagnose(closureExpr->getEndLoc(), + diag::cannot_convert_closure_result, resultType, + expectedResultType); + return true; + } + + // Looks like both actual and expected result types match, + // there is nothing we can diagnose in this case. + return false; + } + + // If we got a result type, let's re-typecheck the function using it, + // maybe we can find a problem where contextually we expect one type + // but trailing closure produces completely different one. + auto fnType = paramType->getAs(); + if (!fnType) + return false; + + auto expectedArgType = FunctionType::get(fnType->getInput(), resultType, + fnType->getExtInfo()); + + auto expectedType = + FunctionType::get(expectedArgType, CS->getContextualType()); + + class ClosureCalleeListener : public ExprTypeCheckListener { + Type contextualType; + + public: + explicit ClosureCalleeListener(Type contextualType) + : contextualType(contextualType) {} + + bool builtConstraints(ConstraintSystem &cs, Expr *expr) override { + cs.addConstraint(ConstraintKind::Conversion, cs.getType(expr), + contextualType, cs.getConstraintLocator(expr), + /*isFavored*/ true); + return false; + } + }; + + ClosureCalleeListener listener(expectedType); + return !typeCheckChildIndependently(callExpr->getFn(), Type(), + CTP_CalleeResult, TCC_ForceRecheck, + &listener); + }; + + // Let's see if there are any structural problems with closure itself. + if (diagnoseClosureExpr(closureExpr, paramType, processor)) + return true; + } + + return false; +} + +/// Check if there failure associated with expresssion is related +/// to given contextual type. +bool FailureDiagnosis::diagnoseCallContextualConversionErrors( + ApplyExpr *callExpr, Type contextualType) { + if (!contextualType || contextualType->hasUnresolvedType()) + return false; + + auto &TC = CS->TC; + auto *DC = CS->DC; + + auto typeCheckExpr = [](TypeChecker &TC, Expr *expr, DeclContext *DC, + SmallVectorImpl &types, + Type contextualType = Type()) { + CalleeListener listener(contextualType); + TC.getPossibleTypesOfExpressionWithoutApplying( + expr, DC, types, FreeTypeVariableBinding::Disallow, &listener); + }; + + // First let's type-check expression without contextual type, and + // see if that's going to produce a type, if so, let's type-check + // again, this time using given contextual type. + SmallVector withoutContextual; + typeCheckExpr(TC, callExpr, DC, withoutContextual); + + // If there are no types returned, it means that problem was + // nothing to do with contextual information, probably parameter/argument + // mismatch. + if (withoutContextual.empty()) + return false; + + SmallVector withContextual; + typeCheckExpr(TC, callExpr, DC, withContextual, contextualType); + // If type-checking with contextual type didn't produce any results + // it means that we have a contextual mismatch. + if (withContextual.empty()) + return diagnoseContextualConversionError(callExpr, contextualType); + + // If call produces a single type when type-checked with contextual + // expression, it means that the problem is elsewhere, any other + // outcome is ambiguous. + return false; +} + +// Check if there is a structural problem in the function expression +// by performing type checking with the option to allow unresolved +// type variables. If that is going to produce a function type with +// unresolved result let's not re-typecheck the function expression, +// because it might produce unrelated diagnostics due to lack of +// contextual information. +static bool shouldTypeCheckFunctionExpr(TypeChecker &TC, DeclContext *DC, + Expr *fnExpr) { + if (!isa(fnExpr)) + return true; + + SmallVector fnTypes; + TC.getPossibleTypesOfExpressionWithoutApplying(fnExpr, DC, fnTypes, + FreeTypeVariableBinding::UnresolvedType); + + if (fnTypes.size() == 1) { + // Some member types depend on the arguments to produce a result type, + // type-checking such expressions without associated arguments is + // going to produce unrelated diagnostics. + if (auto fn = fnTypes[0]->getAs()) { + auto resultType = fn->getResult(); + if (resultType->hasUnresolvedType() || resultType->hasTypeVariable()) + return false; + } + } + + // Might be a structural problem related to the member itself. + return true; +} + bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) { - // Type check the function subexpression to resolve a type for it if possible. - auto fnExpr = typeCheckChildIndependently(callExpr->getFn()); - if (!fnExpr) return true; + // If this call involves trailing closure as an argument, + // let's treat it specially, because re-typecheck of the + // either function or arguments might results in diagnosing + // of the unrelated problems due to luck of context. + if (diagnoseTrailingClosureErrors(callExpr)) + return true; + + if (diagnoseCallContextualConversionErrors(callExpr, CS->getContextualType())) + return true; + + auto *fnExpr = callExpr->getFn(); + auto originalFnType = CS->getType(callExpr->getFn()); + + if (shouldTypeCheckFunctionExpr(CS->TC, CS->DC, fnExpr)) { + // Type check the function subexpression to resolve a type for it if + // possible. + fnExpr = typeCheckChildIndependently(callExpr->getFn()); + if (!fnExpr) + return true; + } SWIFT_DEFER { if (!fnExpr) return; @@ -5974,6 +6304,33 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) { auto fnType = getFuncType(CS->getType(fnExpr)); + // Let's see if this has to do with member vs. property error + // because sometimes when there is a member and a property declared + // on the nominal type with the same name. Type-checking function + // expression separately from arguments might produce solution for + // the property instead of the member. + if (!fnType->is() && + isa(callExpr->getFn())) { + fnExpr = callExpr->getFn(); + + SmallVector types; + CS->TC.getPossibleTypesOfExpressionWithoutApplying(fnExpr, CS->DC, types); + + auto isFunctionType = [getFuncType](Type type) -> bool { + return type && getFuncType(type)->is(); + }; + + auto fnTypes = std::find_if(types.begin(), types.end(), isFunctionType); + if (fnTypes != types.end()) { + auto funcType = getFuncType(*fnTypes); + // If there is only one function type, let's use it. + if (std::none_of(std::next(fnTypes), types.end(), isFunctionType)) + fnType = funcType; + } else { + fnType = getFuncType(originalFnType); + } + } + // If we have a contextual type, and if we have an ambiguously typed function // result from our previous check, we re-type-check it using this contextual // type to inform the result type of the callee. @@ -6022,9 +6379,8 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) { auto arg = callExpr->getArg(); { - auto diag = - diagnose(arg->getStartLoc(), diag::cannot_call_non_function_value, - CS->getType(fnExpr)); + auto diag = diagnose(arg->getStartLoc(), + diag::cannot_call_non_function_value, fnType); diag.highlight(fnExpr->getSourceRange()); // If the argument is an empty tuple, then offer a @@ -6114,6 +6470,23 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) { } } + // If there is a failing constraint associated with current constraint + // system which points to the argument/parameter mismatch, let's use + // that information while re-typechecking argument expression, this + // makes it a lot easier to determine contextual mismatch. + if (CS->failedConstraint && !hasTrailingClosure) { + auto *constraint = CS->failedConstraint; + if (constraint->getKind() == ConstraintKind::ArgumentTupleConversion) { + if (auto *locator = constraint->getLocator()) { + if (locator->getAnchor() == callExpr) { + argType = constraint->getSecondType(); + if (auto *typeVar = argType->getAs()) + argType = CS->getFixedType(typeVar); + } + } + } + } + // Get the expression result of type checking the arguments to the call // independently, so we have some idea of what we're working with. // @@ -6592,9 +6965,36 @@ visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E) { return false; } +static bool isInvalidClosureResultType(Type resultType) { + return !resultType || resultType->hasUnresolvedType() || + resultType->hasTypeVariable() || resultType->hasArchetype(); +} bool FailureDiagnosis::visitClosureExpr(ClosureExpr *CE) { - auto contextualType = CS->getContextualType(); + return diagnoseClosureExpr( + CE, CS->getContextualType(), + [&](Type resultType, Type expectedResultType) -> bool { + if (isInvalidClosureResultType(expectedResultType)) + return false; + + // Following situations are possible: + // * No result type - possible structurable problem in the body; + // * Function result type - possible use of function without calling it, + // which is properly diagnosed by actual type-check call. + if (resultType && !resultType->getRValueType()->is()) { + if (!resultType->isEqual(expectedResultType)) { + diagnose(CE->getEndLoc(), diag::cannot_convert_closure_result, + resultType, expectedResultType); + return true; + } + } + return false; + }); +} + +bool FailureDiagnosis::diagnoseClosureExpr( + ClosureExpr *CE, Type contextualType, + std::function resultTypeProcessor) { // Look through IUO because it doesn't influence // neither parameter nor return type diagnostics itself, // but if we have function type inside, that might @@ -6755,7 +7155,7 @@ bool FailureDiagnosis::visitClosureExpr(ClosureExpr *CE) { // - if the there is a result type associated with the closure; // - and it's not a void type; // - and it hasn't been explicitly written. - auto resultType = CS->getResultType(CE); + auto resultType = fnType->getResult(); auto hasResult = [](Type resultType) -> bool { return resultType && !resultType->isVoid(); }; @@ -6875,6 +7275,9 @@ bool FailureDiagnosis::visitClosureExpr(ClosureExpr *CE) { if (!CE->hasSingleExpressionBody()) return false; + if (isInvalidClosureResultType(expectedResultType)) + expectedResultType = Type(); + // When we're type checking a single-expression closure, we need to reset the // DeclContext to this closure for the recursive type checking. Otherwise, // if there is a closure in the subexpression, we can violate invariants. @@ -6900,19 +7303,8 @@ bool FailureDiagnosis::visitClosureExpr(ClosureExpr *CE) { auto type = CS->TC.getTypeOfExpressionWithoutApplying( closure, CS->DC, decl, FreeTypeVariableBinding::Disallow); - Type resultType = type.hasValue() ? *type : Type(); - - // Following situations are possible: - // * No result type - possible structurable problem in the body; - // * Function result type - possible use of function without calling it, - // which is properly diagnosed by actual type-check call. - if (resultType && !resultType->getRValueType()->is()) { - if (!resultType->isEqual(expectedResultType)) { - diagnose(closure->getEndLoc(), diag::cannot_convert_closure_result, - resultType, expectedResultType); - return true; - } - } + if (type && resultTypeProcessor(*type, expectedResultType)) + return true; } // If the closure had an expected result type, use it. @@ -6923,9 +7315,14 @@ bool FailureDiagnosis::visitClosureExpr(ClosureExpr *CE) { // let's run proper type-check with expected type and try to verify it. auto CTP = expectedResultType ? CTP_ClosureResult : CTP_Unused; - if (!typeCheckChildIndependently(CE->getSingleExpressionBody(), - expectedResultType, CTP, TCCOptions(), - nullptr, false)) + auto *bodyExpr = typeCheckChildIndependently(CE->getSingleExpressionBody(), + expectedResultType, CTP, + TCCOptions(), nullptr, false); + + if (!bodyExpr) + return true; + + if (resultTypeProcessor(bodyExpr->getType(), expectedResultType)) return true; } @@ -6937,12 +7334,18 @@ bool FailureDiagnosis::visitClosureExpr(ClosureExpr *CE) { if (!fnType || fnType->isEqual(CS->getType(CE))) return false; + auto contextualResultType = fnType->getResult(); + // If the result type was unknown, it doesn't really make + // sense to diagnose from expected to unknown here. + if (isInvalidClosureResultType(contextualResultType)) + return false; + // If the closure had an explicitly written return type incompatible with // the contextual type, diagnose that. if (CE->hasExplicitResultType() && CE->getExplicitResultTypeLoc().getTypeRepr()) { auto explicitResultTy = CE->getExplicitResultTypeLoc().getType(); - if (fnType && !explicitResultTy->isEqual(fnType->getResult())) { + if (fnType && !explicitResultTy->isEqual(contextualResultType)) { auto repr = CE->getExplicitResultTypeLoc().getTypeRepr(); diagnose(repr->getStartLoc(), diag::incorrect_explicit_closure_result, explicitResultTy, fnType->getResult()) @@ -7142,7 +7545,7 @@ static bool diagnoseKeyPathComponents(ConstraintSystem *CS, KeyPathExpr *KPE, switch (auto kind = component.getKind()) { case KeyPathExpr::Component::Kind::UnresolvedProperty: { auto componentFullName = component.getUnresolvedDeclName(); - componentName = componentFullName.getBaseName(); + componentName = componentFullName.getBaseIdentifier(); break; } @@ -8248,7 +8651,7 @@ void ConstraintSystem::diagnoseFailureForExpr(Expr *expr) { return; // If this is a contextual conversion problem, dig out some information. - if (diagnosis.diagnoseContextualConversionError()) + if (diagnosis.diagnoseContextualConversionError(expr, getContextualType())) return; // If we can diagnose a problem based on the constraints left laying around in diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 3535edfb4fd..70ab7b2a117 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2848,15 +2848,9 @@ namespace { case KeyPathExpr::Component::Kind::OptionalChain: { didOptionalChain = true; - // TODO: This currently crashes the compiler in some cases, so short- - // circuit out. - if (!CS.TC.Context.LangOpts.EnableExperimentalKeyPathComponents) { - return ErrorType::get(CS.TC.Context); - } - // We can't assign an optional back through an optional chain // today. Force the base to an rvalue. - auto rvalueTy = CS.createTypeVariable(locator, TVO_CanBindToInOut); + auto rvalueTy = CS.createTypeVariable(locator, 0); CS.addConstraint(ConstraintKind::Equal, base, rvalueTy, locator); base = rvalueTy; LLVM_FALLTHROUGH; diff --git a/lib/Sema/CSRanking.cpp b/lib/Sema/CSRanking.cpp index ce1cd3fba56..21809d878b0 100644 --- a/lib/Sema/CSRanking.cpp +++ b/lib/Sema/CSRanking.cpp @@ -85,6 +85,9 @@ void ConstraintSystem::increaseScore(ScoreKind kind, unsigned value) { } bool ConstraintSystem::worseThanBestSolution() const { + if (retainAllSolutions()) + return false; + if (!solverState || !solverState->BestScore || CurrentScore <= *solverState->BestScore) return false; @@ -679,12 +682,12 @@ static bool isDeclAsSpecializedAs(TypeChecker &tc, DeclContext *dc, // second type's inputs, i.e., can we forward the arguments? auto funcTy1 = openedType1->castTo(); auto funcTy2 = openedType2->castTo(); - SmallVector params1 = - decomposeParamType(funcTy1->getInput(), decl1, - outerDC1->isTypeContext()); - SmallVector params2 = - decomposeParamType(funcTy2->getInput(), decl2, - outerDC2->isTypeContext()); + auto params1 = funcTy1->getParams(); + auto params2 = funcTy2->getParams(); + SmallVector defaultMapType2; + computeDefaultMap(funcTy2->getInput(), decl2, + outerDC2->isTypeContext(), + defaultMapType2); unsigned numParams1 = params1.size(); unsigned numParams2 = params2.size(); @@ -694,8 +697,8 @@ static bool isDeclAsSpecializedAs(TypeChecker &tc, DeclContext *dc, bool compareTrailingClosureParamsSeparately = false; if (!tc.getLangOpts().isSwiftVersion3()) { if (numParams1 > 0 && numParams2 > 0 && - params1.back().Ty->is() && - params2.back().Ty->is()) { + params1.back().getType()->is() && + params2.back().getType()->is()) { compareTrailingClosureParamsSeparately = true; --numParams1; --numParams2; @@ -703,7 +706,8 @@ static bool isDeclAsSpecializedAs(TypeChecker &tc, DeclContext *dc, } auto maybeAddSubtypeConstraint = - [&](const CallArgParam ¶m1, const CallArgParam ¶m2) -> bool{ + [&](const AnyFunctionType::Param ¶m1, + const AnyFunctionType::Param ¶m2) -> bool { // If one parameter is variadic and the other is not... if (param1.isVariadic() != param2.isVariadic()) { // If the first parameter is the variadic one, it's not @@ -714,8 +718,8 @@ static bool isDeclAsSpecializedAs(TypeChecker &tc, DeclContext *dc, } // Check whether the first parameter is a subtype of the second. - cs.addConstraint(ConstraintKind::Subtype, param1.Ty, param2.Ty, - locator); + cs.addConstraint(ConstraintKind::Subtype, + param1.getType(), param2.getType(), locator); return true; }; @@ -726,7 +730,7 @@ static bool isDeclAsSpecializedAs(TypeChecker &tc, DeclContext *dc, // We need either a default argument or a variadic // argument for the first declaration to be more // specialized. - if (!params2[i].HasDefaultArgument && + if (!defaultMapType2[i] && !params2[i].isVariadic()) return false; diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index f364fcb9534..ede0a702472 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -86,28 +86,29 @@ areConservativelyCompatibleArgumentLabels(ValueDecl *decl, auto fn = dyn_cast(decl); if (!fn) return true; assert(parameterDepth < fn->getNumParameterLists()); - - ParameterList ¶ms = *fn->getParameterList(parameterDepth); - - SmallVector argInfos; + + auto *fTy = fn->getInterfaceType()->castTo(); + + SmallVector argInfos; for (auto argLabel : labels) { - argInfos.push_back(CallArgParam()); - argInfos.back().Label = argLabel; + argInfos.push_back(AnyFunctionType::Param(Type(), argLabel, {})); } - SmallVector paramInfos; - for (auto param : params) { - paramInfos.push_back(CallArgParam()); - paramInfos.back().Label = param->getArgumentName(); - paramInfos.back().HasDefaultArgument = param->isDefaultArgument(); - paramInfos.back().parameterFlags = ParameterTypeFlags::fromParameterType( - param->getInterfaceType(), param->isVariadic()); + const AnyFunctionType *levelTy = fTy; + for (auto level = parameterDepth; level != 0; --level) { + levelTy = levelTy->getResult()->getAs(); + assert(levelTy && "Parameter list curry level does not match type"); } - + + auto params = levelTy->getParams(); + SmallVector defaultMap; + computeDefaultMap(levelTy->getInput(), decl, parameterDepth, defaultMap); + MatchCallArgumentListener listener; SmallVector unusedParamBindings; - return !matchCallArguments(argInfos, paramInfos, hasTrailingClosure, + return !matchCallArguments(argInfos, params, defaultMap, + hasTrailingClosure, /*allow fixes*/ false, listener, unusedParamBindings); } @@ -120,12 +121,15 @@ static ConstraintSystem::TypeMatchOptions getDefaultDecompositionOptions( } bool constraints:: -matchCallArguments(ArrayRef args, - ArrayRef params, +matchCallArguments(ArrayRef args, + ArrayRef params, + const SmallVectorImpl &defaultMap, bool hasTrailingClosure, bool allowFixes, MatchCallArgumentListener &listener, SmallVectorImpl ¶meterBindings) { + assert(params.size() == defaultMap.size() && "Default map does not match"); + // Keep track of the parameter we're matching and what argument indices // got bound to each parameter. unsigned paramIdx, numParams = params.size(); @@ -154,7 +158,7 @@ matchCallArguments(ArrayRef args, if (!actualArgNames.empty()) { // We're recording argument names; record this one. actualArgNames[argNumber] = expectedName; - } else if (args[argNumber].Label != expectedName && !ignoreNameClash) { + } else if (args[argNumber].getLabel() != expectedName && !ignoreNameClash) { // We have an argument name mismatch. Start recording argument names. actualArgNames.resize(numArgs); @@ -164,7 +168,7 @@ matchCallArguments(ArrayRef args, bool firstArg = true; for (auto argIdx : parameterBindings[i]) { - actualArgNames[argIdx] = firstArg ? param.Label : Identifier(); + actualArgNames[argIdx] = firstArg ? param.getLabel() : Identifier(); firstArg = false; } } @@ -201,7 +205,7 @@ matchCallArguments(ArrayRef args, // Nothing to claim. if (nextArgIdx == numArgs || claimedArgs[nextArgIdx] || - (args[nextArgIdx].hasLabel() && !ignoreNameMismatch)) + (!(args[nextArgIdx].getLabel().empty() || ignoreNameMismatch))) return None; return claim(name, nextArgIdx); @@ -209,7 +213,7 @@ matchCallArguments(ArrayRef args, // If the name matches, claim this argument. if (nextArgIdx != numArgs && - (ignoreNameMismatch || args[nextArgIdx].Label == name)) { + (ignoreNameMismatch || args[nextArgIdx].getLabel() == name)) { return claim(name, nextArgIdx); } @@ -218,7 +222,7 @@ matchCallArguments(ArrayRef args, Optional claimedWithSameName; for (unsigned i = nextArgIdx; i != numArgs; ++i) { // Skip arguments where the name doesn't match. - if (args[i].Label != name) + if (args[i].getLabel() != name) continue; // Skip claimed arguments. @@ -258,7 +262,7 @@ matchCallArguments(ArrayRef args, } // Missing a keyword argument name. - if (nextArgIdx != numArgs && !args[nextArgIdx].hasLabel() && + if (nextArgIdx != numArgs && args[nextArgIdx].getLabel().empty() && ignoreNameMismatch) { // Claim the next argument. return claim(name, nextArgIdx); @@ -277,7 +281,7 @@ matchCallArguments(ArrayRef args, // Handle variadic parameters. if (param.isVariadic()) { // Claim the next argument with the name of this parameter. - auto claimed = claimNextNamed(param.Label, ignoreNameMismatch); + auto claimed = claimNextNamed(param.getLabel(), ignoreNameMismatch); // If there was no such argument, leave the argument unf if (!claimed) { @@ -298,7 +302,7 @@ matchCallArguments(ArrayRef args, } // Try to claim an argument for this parameter. - if (auto claimed = claimNextNamed(param.Label, ignoreNameMismatch)) { + if (auto claimed = claimNextNamed(param.getLabel(), ignoreNameMismatch)) { parameterBindings[paramIdx].push_back(*claimed); skipClaimedArgs(); return; @@ -328,7 +332,7 @@ matchCallArguments(ArrayRef args, llvm::SmallVector unclaimedNamedArgs; for (nextArgIdx = 0; skipClaimedArgs(), nextArgIdx != numArgs; ++nextArgIdx) { - if (args[nextArgIdx].hasLabel()) + if (!args[nextArgIdx].getLabel().empty()) unclaimedNamedArgs.push_back(nextArgIdx); } @@ -338,10 +342,10 @@ matchCallArguments(ArrayRef args, bool hasUnfulfilledUnnamedParams = false; for (paramIdx = 0; paramIdx != numParams; ++paramIdx) { if (parameterBindings[paramIdx].empty()) { - if (params[paramIdx].hasLabel()) - unfulfilledNamedParams.push_back(paramIdx); - else + if (params[paramIdx].getLabel().empty()) hasUnfulfilledUnnamedParams = true; + else + unfulfilledNamedParams.push_back(paramIdx); } } @@ -350,14 +354,14 @@ matchCallArguments(ArrayRef args, // FIXME: There is undoubtedly a good dynamic-programming algorithm // to find the best assignment here. for (auto argIdx : unclaimedNamedArgs) { - auto argName = args[argIdx].Label; + auto argName = args[argIdx].getLabel(); // Find the closest matching unfulfilled named parameter. unsigned bestScore = 0; unsigned best = 0; for (unsigned i = 0, n = unfulfilledNamedParams.size(); i != n; ++i) { unsigned param = unfulfilledNamedParams[i]; - auto paramName = params[param].Label; + auto paramName = params[param].getLabel(); if (auto score = scoreParamAndArgNameTypo(paramName.str(), argName.str(), @@ -434,7 +438,7 @@ matchCallArguments(ArrayRef args, continue; // Parameters with defaults can be unfulfilled. - if (param.HasDefaultArgument) + if (defaultMap[paramIdx]) continue; listener.missingArgument(paramIdx); @@ -473,20 +477,20 @@ matchCallArguments(ArrayRef args, // doesn't provide either, problem is going to be identified as // out-of-order argument instead of label mismatch. auto ¶meter = params[prevArgIdx]; - if (parameter.hasLabel()) { - auto expectedLabel = parameter.Label; - auto argumentLabel = args[argIdx].Label; - + if (!parameter.getLabel().empty()) { + auto expectedLabel = parameter.getLabel(); + auto argumentLabel = args[argIdx].getLabel(); + // If there is a label but it's incorrect it can only mean // situation like this: expected (x, _ y) got (y, _ x). if (argumentLabel.empty() || (expectedLabel.compare(argumentLabel) != 0 && - args[prevArgIdx].Label.empty())) { + args[prevArgIdx].getLabel().empty())) { listener.missingLabel(prevArgIdx); return true; } } - + listener.outOfOrderArgument(argIdx, prevArgIdx); return true; } @@ -654,8 +658,13 @@ matchCallArguments(ConstraintSystem &cs, ConstraintKind kind, bool hasTrailingClosure = false; std::tie(callee, calleeLevel, argLabels, hasTrailingClosure) = getCalleeDeclAndArgs(cs, locator, argLabelsScratch); - auto params = decomposeParamType(paramType, callee, calleeLevel); - + + SmallVector params; + AnyFunctionType::decomposeInput(paramType, params); + + SmallVector defaultMap; + computeDefaultMap(paramType, callee, calleeLevel, defaultMap); + if (callee && cs.getASTContext().isSwiftVersion3() && argType->is()) { // Hack: In Swift 3 mode, accept `foo(x, y)` for `foo((x, y))` when the @@ -673,11 +682,13 @@ matchCallArguments(ConstraintSystem &cs, ConstraintKind kind, // Extract the arguments. auto args = decomposeArgType(argType, argLabels); - + // Match up the call arguments to the parameters. MatchCallArgumentListener listener; SmallVector parameterBindings; - if (constraints::matchCallArguments(args, params, hasTrailingClosure, + if (constraints::matchCallArguments(args, params, + defaultMap, + hasTrailingClosure, cs.shouldAttemptFixes(), listener, parameterBindings)) return ConstraintSystem::SolutionKind::Error; @@ -735,14 +746,14 @@ matchCallArguments(ConstraintSystem &cs, ConstraintKind kind, // Determine the parameter type. const auto ¶m = params[paramIdx]; - auto paramTy = param.Ty; + auto paramTy = param.getType(); // Compare each of the bound arguments for this parameter. for (auto argIdx : parameterBindings[paramIdx]) { auto loc = locator.withPathElement(LocatorPathElt:: getApplyArgToParam(argIdx, paramIdx)); - auto argTy = args[argIdx].Ty; + auto argTy = args[argIdx].getType(); if (!haveOneNonUserConversion) { subflags |= ConstraintSystem::TMF_ApplyingOperatorParameter; @@ -1042,11 +1053,28 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2, increaseScore(ScoreKind::SK_FunctionConversion); + // Add a very narrow exception to SE-0110 by allowing functions that + // take multiple arguments to be passed as an argument in places + // that expect a function that takes a single tuple (of the same + // arity). + auto func1Input = func1->getInput(); + auto func2Input = func2->getInput(); + if (!getASTContext().isSwiftVersion3()) { + if (auto elt = locator.last()) { + if (elt->getKind() == ConstraintLocator::ApplyArgToParam) { + if (auto *paren2 = dyn_cast(func2Input.getPointer())) { + func2Input = paren2->getUnderlyingType(); + if (auto *paren1 = dyn_cast(func1Input.getPointer())) + func1Input = paren1->getUnderlyingType(); + } + } + } + } + // Input types can be contravariant (or equal). - SolutionKind result = matchTypes(func2->getInput(), func1->getInput(), - subKind, subflags, - locator.withPathElement( - ConstraintLocator::FunctionArgument)); + SolutionKind result = + matchTypes(func2Input, func1Input, subKind, subflags, + locator.withPathElement(ConstraintLocator::FunctionArgument)); if (result == SolutionKind::Error) return SolutionKind::Error; @@ -1355,7 +1383,9 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, typeVar2 = dyn_cast(type2.getPointer()); // If the types are obviously equivalent, we're done. - if (type1.getPointer() == type2.getPointer()) + if (isa(type1.getPointer()) == + isa(type2.getPointer()) && + type1->isEqual(type2)) return SolutionKind::Solved; } else { typeVar1 = desugar1->getAs(); @@ -2473,17 +2503,27 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint( // separately. switch (kind) { case ConstraintKind::SelfObjectOfProtocol: - if (TC.containsProtocol(type, protocol, DC, - ConformanceCheckFlags::InExpression)) + if (auto conformance = + TC.containsProtocol(type, protocol, DC, + ConformanceCheckFlags::InExpression)) { + CheckedConformances.push_back({getConstraintLocator(locator), + *conformance}); return SolutionKind::Solved; + } break; case ConstraintKind::ConformsTo: - case ConstraintKind::LiteralConformsTo: + case ConstraintKind::LiteralConformsTo: { // Check whether this type conforms to the protocol. - if (TC.conformsToProtocol(type, protocol, DC, - ConformanceCheckFlags::InExpression)) + if (auto conformance = + TC.conformsToProtocol(type, protocol, DC, + ConformanceCheckFlags::InExpression)) { + CheckedConformances.push_back({getConstraintLocator(locator), + *conformance}); return SolutionKind::Solved; + } break; + } + default: llvm_unreachable("bad constraint kind"); } diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp index 1a82c540432..fbd0205973e 100644 --- a/lib/Sema/CSSolver.cpp +++ b/lib/Sema/CSSolver.cpp @@ -110,7 +110,7 @@ Solution ConstraintSystem::finalize( Solution solution(*this, CurrentScore); // Update the best score we've seen so far. - if (solverState) { + if (solverState && !retainAllSolutions()) { assert(!solverState->BestScore || CurrentScore <= *solverState->BestScore); solverState->BestScore = CurrentScore; } @@ -201,6 +201,9 @@ Solution ConstraintSystem::finalize( solution.DefaultedConstraints.insert(DefaultedConstraints.begin(), DefaultedConstraints.end()); + for (auto &e : CheckedConformances) + solution.Conformances.push_back({e.first, e.second}); + return solution; } @@ -261,6 +264,10 @@ void ConstraintSystem::applySolution(const Solution &solution) { DefaultedConstraints.append(solution.DefaultedConstraints.begin(), solution.DefaultedConstraints.end()); + // Register the conformances checked along the way to arrive to solution. + for (auto &conformance : solution.Conformances) + CheckedConformances.push_back(conformance); + // Register any fixes produced along this path. Fixes.append(solution.Fixes.begin(), solution.Fixes.end()); } @@ -452,6 +459,7 @@ ConstraintSystem::SolverScope::SolverScope(ConstraintSystem &cs) numOpenedTypes = cs.OpenedTypes.size(); numOpenedExistentialTypes = cs.OpenedExistentialTypes.size(); numDefaultedConstraints = cs.DefaultedConstraints.size(); + numCheckedConformances = cs.CheckedConformances.size(); PreviousScore = cs.CurrentScore; cs.solverState->registerScope(this); @@ -502,7 +510,10 @@ ConstraintSystem::SolverScope::~SolverScope() { // Remove any defaulted type variables. truncate(cs.DefaultedConstraints, numDefaultedConstraints); - + + // Remove any conformances checked along the current path. + truncate(cs.CheckedConformances, numCheckedConformances); + // Reset the previous score. cs.CurrentScore = PreviousScore; @@ -1488,7 +1499,8 @@ bool ConstraintSystem::Candidate::solve( }; // Allocate new constraint system for sub-expression. - ConstraintSystem cs(TC, DC, None); + ConstraintSystem cs(TC, DC, + ConstraintSystemFlags::ReturnAllDiscoveredSolutions); // Cleanup after constraint system generation/solving, // because it would assign types to expressions, which @@ -1974,6 +1986,10 @@ ConstraintSystem::solve(Expr *&expr, assert(!solverState && "use solveRec for recursive calls"); + // Set up the expression type checker timer. + Timer.emplace(expr, TC.getDebugTimeExpressions(), + TC.getWarnLongExpressionTypeChecking(), TC.Context); + // Try to shrink the system by reducing disjunction domains. This // goes through every sub-expression and generate its own sub-system, to // try to reduce the domains of those subexpressions. @@ -2055,16 +2071,11 @@ bool ConstraintSystem::solve(SmallVectorImpl &solutions, // Solve the system. solveRec(solutions, allowFreeTypeVariables); - // If there is more than one viable system, attempt to pick the best - // solution. - auto size = solutions.size(); - if (size > 1) { - if (auto best = findBestSolution(solutions, /*minimize=*/false)) { - if (*best != 0) - solutions[0] = std::move(solutions[*best]); - solutions.erase(solutions.begin() + 1, solutions.end()); - } - } + // Filter deduced solutions, try to figure out if there is + // a single best solution to use, if not explicitly disabled + // by constraint system options. + if (!retainAllSolutions()) + filterSolutions(solutions); // We fail if there is no solution. return solutions.empty(); @@ -2277,11 +2288,8 @@ bool ConstraintSystem::solveRec(SmallVectorImpl &solutions, auto &solutions = partialSolutions[component]; // If there's a single best solution, keep only that one. // Otherwise, the set of solutions will at least have been minimized. - if (auto best = findBestSolution(solutions, /*minimize=*/true)) { - if (*best > 0) - solutions[0] = std::move(solutions[*best]); - solutions.erase(solutions.begin() + 1, solutions.end()); - } + if (!retainAllSolutions()) + filterSolutions(solutions, /*minimize=*/true); } // Produce all combinations of partial solutions. diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index 9fb20e19752..9589abdebb2 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -352,18 +352,15 @@ static FuncDecl *createMaterializeForSetPrototype(AbstractStorageDecl *storage, params, TypeLoc::withoutLoc(retTy), DC); materializeForSet->setImplicit(); - bool isStatic = storage->isStatic(); - // Open-code the setMutating() calculation since we might run before - // the setter has been type checked. Also as a hack, always mark the - // setter mutating if we're inside a protocol, because it seems some - // things break otherwise -- the root cause should be fixed eventually. + // the setter has been type checked. + Type contextTy = DC->getDeclaredInterfaceType(); materializeForSet->setMutating( - storage->getDeclContext()->getAsProtocolOrProtocolExtensionContext() || - (!setter->getAttrs().hasAttribute() && - !storage->isSetterNonMutating())); + contextTy && !contextTy->hasReferenceSemantics() && + !setter->getAttrs().hasAttribute() && + !storage->isSetterNonMutating()); - materializeForSet->setStatic(isStatic); + materializeForSet->setStatic(storage->isStatic()); // materializeForSet is final if the storage is. if (storage->isFinal()) diff --git a/lib/Sema/ConstraintGraph.cpp b/lib/Sema/ConstraintGraph.cpp index 5cd63e94e1f..4937aea56d2 100644 --- a/lib/Sema/ConstraintGraph.cpp +++ b/lib/Sema/ConstraintGraph.cpp @@ -467,8 +467,8 @@ void ConstraintGraph::gatherConstraints( TypeVariableType *typeVar, SmallVectorImpl &constraints, GatheringKind kind) { - auto &node = (*this)[CS.getRepresentative(typeVar)]; - auto equivClass = node.getEquivalenceClass(); + auto &reprNode = (*this)[CS.getRepresentative(typeVar)]; + auto equivClass = reprNode.getEquivalenceClass(); llvm::SmallPtrSet typeVars; for (auto typeVar : equivClass) { if (!typeVars.insert(typeVar).second) @@ -476,38 +476,40 @@ void ConstraintGraph::gatherConstraints( for (auto constraint : (*this)[typeVar].getConstraints()) constraints.push_back(constraint); - } - // Retrieve the constraints from adjacent bindings. - for (auto adjTypeVar : node.getAdjacencies()) { - switch (kind) { - case GatheringKind::EquivalenceClass: - if (!node.getAdjacency(adjTypeVar).FixedBinding) - continue; - break; + auto &node = (*this)[typeVar]; - case GatheringKind::AllMentions: - break; - } + // Retrieve the constraints from adjacent bindings. + for (auto adjTypeVar : node.getAdjacencies()) { + switch (kind) { + case GatheringKind::EquivalenceClass: + if (!node.getAdjacency(adjTypeVar).FixedBinding) + continue; + break; - ArrayRef adjTypeVarsToVisit; - switch (kind) { - case GatheringKind::EquivalenceClass: - adjTypeVarsToVisit = adjTypeVar; - break; + case GatheringKind::AllMentions: + break; + } - case GatheringKind::AllMentions: - adjTypeVarsToVisit - = (*this)[CS.getRepresentative(adjTypeVar)].getEquivalenceClass(); - break; - } + ArrayRef adjTypeVarsToVisit; + switch (kind) { + case GatheringKind::EquivalenceClass: + adjTypeVarsToVisit = adjTypeVar; + break; - for (auto adjTypeVarEquiv : adjTypeVarsToVisit) { - if (!typeVars.insert(adjTypeVarEquiv).second) - continue; + case GatheringKind::AllMentions: + adjTypeVarsToVisit + = (*this)[CS.getRepresentative(adjTypeVar)].getEquivalenceClass(); + break; + } - for (auto constraint : (*this)[adjTypeVarEquiv].getConstraints()) - constraints.push_back(constraint); + for (auto adjTypeVarEquiv : adjTypeVarsToVisit) { + if (!typeVars.insert(adjTypeVarEquiv).second) + continue; + + for (auto constraint : (*this)[adjTypeVarEquiv].getConstraints()) + constraints.push_back(constraint); + } } } } diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 4b3970948e8..90dc645c9f2 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -21,12 +21,31 @@ #include "swift/Basic/Statistic.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/Format.h" using namespace swift; using namespace constraints; #define DEBUG_TYPE "ConstraintSystem" +ExpressionTimer::~ExpressionTimer() { + auto elapsed = getElapsedProcessTimeInFractionalSeconds(); + unsigned elapsedMS = static_cast(elapsed * 1000); + + if (ShouldDump) { + // Round up to the nearest 100th of a millisecond. + llvm::errs() << llvm::format("%0.2f", ceil(elapsed * 100000) / 100) + << "ms\t"; + E->getLoc().print(llvm::errs(), Context.SourceMgr); + llvm::errs() << "\n"; + } + + if (WarnLimit != 0 && elapsedMS >= WarnLimit && E->getLoc().isValid()) + Context.Diags.diagnose(E->getLoc(), diag::debug_long_expression, + elapsedMS, WarnLimit) + .highlight(E->getSourceRange()); +} + ConstraintSystem::ConstraintSystem(TypeChecker &tc, DeclContext *dc, ConstraintSystemOptions options) : TC(tc), DC(dc), Options(options), @@ -1753,15 +1772,13 @@ Type Solution::simplifyType(Type type) const { } size_t Solution::getTotalMemory() const { - return sizeof(*this) + - typeBindings.getMemorySize() + - overloadChoices.getMemorySize() + - ConstraintRestrictions.getMemorySize() + - llvm::capacity_in_bytes(Fixes) + - DisjunctionChoices.getMemorySize() + - OpenedTypes.getMemorySize() + - OpenedExistentialTypes.getMemorySize() + - (DefaultedConstraints.size() * sizeof(void*)); + return sizeof(*this) + typeBindings.getMemorySize() + + overloadChoices.getMemorySize() + + ConstraintRestrictions.getMemorySize() + + llvm::capacity_in_bytes(Fixes) + DisjunctionChoices.getMemorySize() + + OpenedTypes.getMemorySize() + OpenedExistentialTypes.getMemorySize() + + (DefaultedConstraints.size() * sizeof(void *)) + + llvm::capacity_in_bytes(Conformances); } DeclName OverloadChoice::getName() const { diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index c96f56aaf68..2b0eebbdc55 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -36,6 +36,7 @@ #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -115,6 +116,35 @@ public: } }; + +class ExpressionTimer { + Expr* E; + unsigned WarnLimit; + bool ShouldDump; + ASTContext &Context; + llvm::TimeRecord StartTime = llvm::TimeRecord::getCurrentTime(); + +public: + ExpressionTimer(Expr *E, bool shouldDump, unsigned warnLimit, + ASTContext &Context) + : E(E), WarnLimit(warnLimit), ShouldDump(shouldDump), Context(Context) { + } + + ~ExpressionTimer(); + + /// Return the elapsed process time (including fractional seconds) + /// as a double. + double getElapsedProcessTimeInFractionalSeconds() { + llvm::TimeRecord endTime = llvm::TimeRecord::getCurrentTime(false); + + return endTime.getProcessTime() - StartTime.getProcessTime(); + } + + // Disable emission of warnings about expressions that take longer + // than the warning threshold. + void disableWarning() { WarnLimit = 0; } +}; + } // end namespace constraints /// Options that describe how a type variable can be used. @@ -562,6 +592,9 @@ public: /// The locators of \c Defaultable constraints whose defaults were used. llvm::SmallPtrSet DefaultedConstraints; + llvm::SmallVector, 8> + Conformances; + /// \brief Simplify the given type by substituting all occurrences of /// type variables for their fixed types. Type simplifyType(Type type) const; @@ -747,6 +780,10 @@ enum class ConstraintSystemFlags { /// Set if the client prefers fixits to be in the form of force unwrapping /// or optional chaining to return an optional. PreferForceUnwrapToOptional = 0x02, + + /// If set, this is going to prevent constraint system from erasing all + /// discovered solutions except the best one. + ReturnAllDiscoveredSolutions = 0x04, }; /// Options that affect the constraint system as a whole. @@ -843,6 +880,7 @@ public: TypeChecker &TC; DeclContext *DC; ConstraintSystemOptions Options; + Optional Timer; friend class Fix; friend class OverloadChoice; @@ -967,6 +1005,9 @@ private: SmallVector, 4> OpenedExistentialTypes; + SmallVector, 8> + CheckedConformances; + public: /// The locators of \c Defaultable constraints whose defaults were used. SmallVector DefaultedConstraints; @@ -1336,6 +1377,8 @@ public: /// The length of \c DefaultedConstraints. unsigned numDefaultedConstraints; + unsigned numCheckedConformances; + /// The previous score. Score PreviousScore; @@ -1370,6 +1413,13 @@ public: bool hasFreeTypeVariables(); private: + /// \brief Indicates if the constraint system should retain all of the + /// solutions it has deduced regardless of their score. + bool retainAllSolutions() const { + return Options.contains( + ConstraintSystemFlags::ReturnAllDiscoveredSolutions); + } + /// \brief Finalize this constraint system; we're done attempting to solve /// it. /// @@ -1391,8 +1441,28 @@ private: /// diagnostic for it and returning true. If the fixit hint turned out to be /// bogus, this returns false and doesn't emit anything. bool applySolutionFix(Expr *expr, const Solution &solution, unsigned fixNo); - - + + /// \brief If there is more than one viable solution, + /// attempt to pick the best solution and remove all of the rest. + /// + /// \param solutions The set of solutions to filter. + /// + /// \param minimize The flag which idicates if the + /// set of solutions should be filtered even if there is + /// no single best solution, see `findBestSolution` for + /// more details. + void filterSolutions(SmallVectorImpl &solutions, + bool minimize = false) { + if (solutions.size() < 2) + return; + + if (auto best = findBestSolution(solutions, minimize)) { + if (*best != 0) + solutions[0] = std::move(solutions[*best]); + solutions.erase(solutions.begin() + 1, solutions.end()); + } + } + /// \brief Restore the type variable bindings to what they were before /// we attempted to solve this constraint system. /// @@ -2513,6 +2583,17 @@ public: /// \brief Determine if we've already explored too many paths in an /// attempt to solve this expression. bool getExpressionTooComplex(SmallVectorImpl const &solutions) { + if (Timer.hasValue()) { + auto elapsed = Timer->getElapsedProcessTimeInFractionalSeconds(); + if (unsigned(elapsed) > TC.getExpressionTimeoutThresholdInSeconds()) { + // Disable warnings about expressions that go over the warning + // threshold since we're arbitrarily ending evaluation and + // emitting an error. + Timer->disableWarning(); + return true; + } + } + if (!getASTContext().isSwiftVersion3()) { if (CountScopes < TypeCounter) return false; @@ -2627,7 +2708,8 @@ public: /// the parameters (as described by the given parameter type). /// /// \param argTuple The arguments. -/// \param paramTuple The parameters. +/// \param params The parameters. +/// \param defaultMap A map indicating if the parameter at that index has a default value. /// \param hasTrailingClosure Whether the last argument is a trailing closure. /// \param allowFixes Whether to allow fixes when matching arguments. /// @@ -2637,8 +2719,9 @@ public: /// \param parameterBindings Will be populated with the arguments that are /// bound to each of the parameters. /// \returns true if the call arguments could not be matched to the parameters. -bool matchCallArguments(ArrayRef argTuple, - ArrayRef paramTuple, +bool matchCallArguments(ArrayRef argTuple, + ArrayRef params, + const SmallVectorImpl &defaultMap, bool hasTrailingClosure, bool allowFixes, MatchCallArgumentListener &listener, diff --git a/lib/Sema/DerivedConformanceCodable.cpp b/lib/Sema/DerivedConformanceCodable.cpp index c8b6b3005b3..d5617a56df4 100644 --- a/lib/Sema/DerivedConformanceCodable.cpp +++ b/lib/Sema/DerivedConformanceCodable.cpp @@ -50,18 +50,18 @@ static bool inheritsConformanceTo(ClassDecl *target, ProtocolDecl *proto) { /// /// \param target The \c ClassDecl whose superclass to check. static bool superclassIsEncodable(ClassDecl *target) { - auto &C = target->getASTContext(); - return inheritsConformanceTo(target, - C.getProtocol(KnownProtocolKind::Encodable)); + auto &C = target->getASTContext(); + return inheritsConformanceTo(target, + C.getProtocol(KnownProtocolKind::Encodable)); } /// Returns whether the superclass of the given class conforms to Decodable. /// /// \param target The \c ClassDecl whose superclass to check. static bool superclassIsDecodable(ClassDecl *target) { - auto &C = target->getASTContext(); - return inheritsConformanceTo(target, - C.getProtocol(KnownProtocolKind::Decodable)); + auto &C = target->getASTContext(); + return inheritsConformanceTo(target, + C.getProtocol(KnownProtocolKind::Decodable)); } /// Represents the possible outcomes of checking whether a decl conforms to @@ -88,29 +88,34 @@ static CodableConformanceType typeConformsToCodable(TypeChecker &tc, ProtocolDecl *proto) { // Some generic types need to be introspected to get at their "true" Codable // conformance. - auto canType = target->getCanonicalType(); - if (auto genericType = dyn_cast(canType)) { + if (auto referenceType = target->getAs()) { + // This is a weak/unowned/unmanaged var. Get the inner type before checking + // conformance. + target = referenceType->getReferentType(); + } + + if (auto genericType = target->getAs()) { auto *nominalTypeDecl = genericType->getAnyNominal(); // Implicitly unwrapped optionals need to be unwrapped; // ImplicitlyUnwrappedOptional does not need to conform to Codable directly // -- only its inner type does. if (nominalTypeDecl == tc.Context.getImplicitlyUnwrappedOptionalDecl() || - // FIXME: Remove the following when conditional conformance lands. - // Some generic types in the stdlib currently conform to Codable even - // when the type they are generic on does not [Optional, Array, Set, - // Dictionary]. For synthesizing conformance, we don't want to - // consider these types as Codable if the nested type is not Codable. - // Look through the generic type parameters of these types recursively - // to avoid synthesizing code that will crash at runtime. - // - // We only want to look through generic params for these types; other - // types may validly conform to Codable even if their generic param - // types do not. - nominalTypeDecl == tc.Context.getOptionalDecl() || - nominalTypeDecl == tc.Context.getArrayDecl() || - nominalTypeDecl == tc.Context.getSetDecl() || - nominalTypeDecl == tc.Context.getDictionaryDecl()) { + // FIXME: Remove the following when conditional conformance lands. + // Some generic types in the stdlib currently conform to Codable even + // when the type they are generic on does not [Optional, Array, Set, + // Dictionary]. For synthesizing conformance, we don't want to + // consider these types as Codable if the nested type is not Codable. + // Look through the generic type parameters of these types recursively + // to avoid synthesizing code that will crash at runtime. + // + // We only want to look through generic params for these types; other + // types may validly conform to Codable even if their generic param + // types do not. + nominalTypeDecl == tc.Context.getOptionalDecl() || + nominalTypeDecl == tc.Context.getArrayDecl() || + nominalTypeDecl == tc.Context.getSetDecl() || + nominalTypeDecl == tc.Context.getDictionaryDecl()) { for (auto paramType : genericType->getGenericArgs()) { if (typeConformsToCodable(tc, context, paramType, proto) != Conforms) return DoesNotConform; @@ -301,9 +306,8 @@ static CodingKeysValidity hasValidCodingKeysEnum(TypeChecker &tc, // CodingKeys may be a typealias. If so, follow the alias to its canonical // type. auto codingKeysType = codingKeysTypeDecl->getDeclaredInterfaceType(); - if (isa(codingKeysTypeDecl)) { + if (isa(codingKeysTypeDecl)) codingKeysTypeDecl = codingKeysType->getAnyNominal(); - } // Ensure that the type we found conforms to the CodingKey protocol. auto *codingKeyProto = C.getProtocol(KnownProtocolKind::CodingKey); @@ -435,9 +439,8 @@ static EnumDecl *lookupEvaluatedCodingKeysEnum(ASTContext &C, return nullptr; auto *codingKeysDecl = codingKeyDecls.front(); - if (auto *typealiasDecl = dyn_cast(codingKeysDecl)) { + if (auto *typealiasDecl = dyn_cast(codingKeysDecl)) codingKeysDecl = typealiasDecl->getDeclaredInterfaceType()->getAnyNominal(); - } return dyn_cast(codingKeysDecl); } @@ -622,6 +625,12 @@ static void deriveBodyEncodable_encode(AbstractFunctionDecl *encodeDecl) { // encode(_:forKey:)/encodeIfPresent(_:forKey:) auto methodName = C.Id_encode; auto varType = cast(matchingVars[0])->getType(); + if (auto referenceType = varType->getAs()) { + // This is a weak/unowned/unmanaged var. Get the inner type before + // checking optionality. + varType = referenceType->getReferentType(); + } + if (varType->getAnyNominal() == C.getOptionalDecl() || varType->getAnyNominal() == C.getImplicitlyUnwrappedOptionalDecl()) { methodName = C.Id_encodeIfPresent; @@ -759,8 +768,7 @@ static FuncDecl *deriveEncodable_encode(TypeChecker &tc, Decl *parentDecl, Type interfaceType; if (auto sig = target->getGenericSignatureOfContext()) { // Evaluate the below, but in a generic environment (if Self is generic). - encodeDecl->setGenericEnvironment( - target->getGenericEnvironmentOfContext()); + encodeDecl->setGenericEnvironment(target->getGenericEnvironmentOfContext()); interfaceType = GenericFunctionType::get(sig, selfType, innerType, FunctionType::ExtInfo()); } else { @@ -883,6 +891,12 @@ static void deriveBodyDecodable_init(AbstractFunctionDecl *initDecl) { // This is also true if the type is an ImplicitlyUnwrappedOptional. auto varType = varDecl->getType(); auto methodName = C.Id_decode; + if (auto referenceType = varType->getAs()) { + // This is a weak/unowned/unmanaged var. Get the inner type before + // checking optionality. + varType = referenceType->getReferentType(); + } + if (varType->getAnyNominal() == C.getOptionalDecl() || varType->getAnyNominal() == C.getImplicitlyUnwrappedOptionalDecl()) { methodName = C.Id_decodeIfPresent; @@ -1111,82 +1125,112 @@ static bool canSynthesize(TypeChecker &tc, NominalTypeDecl *target, } ValueDecl *DerivedConformance::deriveEncodable(TypeChecker &tc, - Decl *parentDecl, - NominalTypeDecl *target, - ValueDecl *requirement) { - // We can only synthesize Encodable for structs and classes. - if (!isa(target) && !isa(target)) - return nullptr; + Decl *parentDecl, + NominalTypeDecl *target, + ValueDecl *requirement) { + // We can only synthesize Encodable for structs and classes. + if (!isa(target) && !isa(target)) + return nullptr; - if (requirement->getBaseName() != tc.Context.Id_encode) { - // Unknown requirement. - tc.diagnose(requirement->getLoc(), diag::broken_encodable_requirement); - return nullptr; - } + if (requirement->getBaseName() != tc.Context.Id_encode) { + // Unknown requirement. + tc.diagnose(requirement->getLoc(), diag::broken_encodable_requirement); + return nullptr; + } - // Conformance can't be synthesized in an extension. - auto encodableProto = tc.Context.getProtocol(KnownProtocolKind::Encodable); - auto encodableType = encodableProto->getDeclaredType(); - if (target != parentDecl) { - tc.diagnose(parentDecl->getLoc(), diag::cannot_synthesize_in_extension, - encodableType); - return nullptr; - } - - // Check other preconditions for synthesized conformance. - // This synthesizes a CodingKeys enum if possible. - if (canSynthesize(tc, target, encodableProto)) - return deriveEncodable_encode(tc, parentDecl, target); - - // Known protocol requirement but could not synthesize. - // FIXME: We have to output at least one error diagnostic here because we - // returned true from NominalTypeDecl::derivesProtocolConformance; if we - // don't, we expect to return a witness here later and crash on an - // assertion. Producing an error stops compilation before then. - tc.diagnose(target, diag::type_does_not_conform, target->getDeclaredType(), + // Conformance can't be synthesized in an extension. + auto encodableProto = tc.Context.getProtocol(KnownProtocolKind::Encodable); + auto encodableType = encodableProto->getDeclaredType(); + if (target != parentDecl) { + tc.diagnose(parentDecl->getLoc(), diag::cannot_synthesize_in_extension, encodableType); + return nullptr; + } + + // We're about to try to synthesize Encodable. If something goes wrong, + // we'll have to output at least one error diagnostic because we returned + // true from NominalTypeDecl::derivesProtocolConformance; if we don't, we're + // expected to return a witness here later (and we crash on an assertion). + // Producing a diagnostic stops compilation before then. + // + // A synthesis attempt will produce NOTE diagnostics throughout, but we'll + // want to collect them before displaying -- we want NOTEs to display + // _after_ a main diagnostic so we don't get a NOTE before the error it + // relates to. + // + // We can do this with a diagnostic transaction -- first collect failure + // diagnostics, then potentially collect notes. If we succeed in + // synthesizing Encodable, we can cancel the transaction and get rid of the + // fake failures. + auto diagnosticTransaction = DiagnosticTransaction(tc.Context.Diags); + tc.diagnose(target, diag::type_does_not_conform, target->getDeclaredType(), + encodableType); + + // Check other preconditions for synthesized conformance. + // This synthesizes a CodingKeys enum if possible. + ValueDecl *witness = nullptr; + if (canSynthesize(tc, target, encodableProto)) + witness = deriveEncodable_encode(tc, parentDecl, target); + + if (witness == nullptr) { + // We didn't end up synthesizing encode(to:). tc.diagnose(requirement, diag::no_witnesses, diag::RequirementKind::Func, requirement->getFullName(), encodableType, /*AddFixIt=*/false); - return nullptr; + } else { + // We succeeded -- no need to output the false error generated above. + diagnosticTransaction.abort(); + } + + return witness; } ValueDecl *DerivedConformance::deriveDecodable(TypeChecker &tc, Decl *parentDecl, NominalTypeDecl *target, ValueDecl *requirement) { - // We can only synthesize Encodable for structs and classes. - if (!isa(target) && !isa(target)) - return nullptr; + // We can only synthesize Encodable for structs and classes. + if (!isa(target) && !isa(target)) + return nullptr; - if (requirement->getBaseName() != tc.Context.Id_init) { - // Unknown requirement. - tc.diagnose(requirement->getLoc(), diag::broken_decodable_requirement); - return nullptr; - } + if (requirement->getBaseName() != tc.Context.Id_init) { + // Unknown requirement. + tc.diagnose(requirement->getLoc(), diag::broken_decodable_requirement); + return nullptr; + } - // Conformance can't be synthesized in an extension. - auto decodableProto = tc.Context.getProtocol(KnownProtocolKind::Decodable); - auto decodableType = decodableProto->getDeclaredType(); - if (target != parentDecl) { - tc.diagnose(parentDecl->getLoc(), diag::cannot_synthesize_in_extension, - decodableType); - return nullptr; - } - - // Check other preconditions for synthesized conformance. - // This synthesizes a CodingKeys enum if possible. - if (canSynthesize(tc, target, decodableProto)) - return deriveDecodable_init(tc, parentDecl, target); - - // Known protocol requirement but could not synthesize. - // FIXME: We have to output at least one error diagnostic here because we - // returned true from NominalTypeDecl::derivesProtocolConformance; if we - // don't, we expect to return a witness here later and crash on an - // assertion. Producing an error stops compilation before then. - tc.diagnose(target, diag::type_does_not_conform, target->getDeclaredType(), + // Conformance can't be synthesized in an extension. + auto decodableProto = tc.Context.getProtocol(KnownProtocolKind::Decodable); + auto decodableType = decodableProto->getDeclaredType(); + if (target != parentDecl) { + tc.diagnose(parentDecl->getLoc(), diag::cannot_synthesize_in_extension, decodableType); + return nullptr; + } + + // We're about to try to synthesize Decodable. If something goes wrong, + // we'll have to output at least one error diagnostic. We need to collate + // diagnostics produced by canSynthesize and deriveDecodable_init to produce + // them in the right order -- see the comment in deriveEncodable for + // background on this transaction. + auto diagnosticTransaction = DiagnosticTransaction(tc.Context.Diags); + tc.diagnose(target, diag::type_does_not_conform, target->getDeclaredType(), + decodableType); + + // Check other preconditions for synthesized conformance. + // This synthesizes a CodingKeys enum if possible. + ValueDecl *witness = nullptr; + if (canSynthesize(tc, target, decodableProto)) + witness = deriveDecodable_init(tc, parentDecl, target); + + if (witness == nullptr) { + // We didn't end up synthesizing init(from:). tc.diagnose(requirement, diag::no_witnesses, diag::RequirementKind::Constructor, requirement->getFullName(), decodableType, /*AddFixIt=*/false); - return nullptr; + } else { + // We succeeded -- no need to output the false error generated above. + diagnosticTransaction.abort(); + } + + return witness; } diff --git a/lib/Sema/DerivedConformanceCodingKey.cpp b/lib/Sema/DerivedConformanceCodingKey.cpp index def94bdad7d..055b9731944 100644 --- a/lib/Sema/DerivedConformanceCodingKey.cpp +++ b/lib/Sema/DerivedConformanceCodingKey.cpp @@ -271,7 +271,7 @@ deriveBodyCodingKey_enum_stringValue(AbstractFunctionDecl *strValDecl) { body = BraceStmt::create(C, SourceLoc(), ASTNode(returnStmt), SourceLoc()); } else { - SmallVector cases; + SmallVector cases; for (auto *elt : elements) { auto *pat = new (C) EnumElementPattern(TypeLoc::withoutLoc(enumType), SourceLoc(), SourceLoc(), @@ -336,7 +336,7 @@ deriveBodyCodingKey_init_stringValue(AbstractFunctionDecl *initDecl) { } auto *selfRef = createSelfDeclRef(initDecl); - SmallVector cases; + SmallVector cases; for (auto *elt : elements) { auto *litExpr = new (C) StringLiteralExpr(elt->getNameStr(), SourceRange(), /*Implicit=*/true); diff --git a/lib/Sema/DerivedConformanceEquatableHashable.cpp b/lib/Sema/DerivedConformanceEquatableHashable.cpp index f0d5ed71f69..6460bd3162f 100644 --- a/lib/Sema/DerivedConformanceEquatableHashable.cpp +++ b/lib/Sema/DerivedConformanceEquatableHashable.cpp @@ -88,7 +88,7 @@ static DeclRefExpr *convertEnumToIndex(SmallVectorImpl &stmts, indexPat, nullptr, funcDecl); unsigned index = 0; - SmallVector cases; + SmallVector cases; for (auto elt : enumDecl->getAllElements()) { // generate: case .: auto pat = new (C) EnumElementPattern(TypeLoc::withoutLoc(enumType), diff --git a/lib/Sema/DerivedConformanceRawRepresentable.cpp b/lib/Sema/DerivedConformanceRawRepresentable.cpp index 9feaad69d69..c4a6a14aaec 100644 --- a/lib/Sema/DerivedConformanceRawRepresentable.cpp +++ b/lib/Sema/DerivedConformanceRawRepresentable.cpp @@ -93,7 +93,7 @@ static void deriveBodyRawRepresentable_raw(AbstractFunctionDecl *toRawDecl) { Type enumType = parentDC->getDeclaredTypeInContext(); - SmallVector cases; + SmallVector cases; for (auto elt : enumDecl->getAllElements()) { auto pat = new (C) EnumElementPattern(TypeLoc::withoutLoc(enumType), SourceLoc(), SourceLoc(), @@ -198,7 +198,7 @@ deriveBodyRawRepresentable_init(AbstractFunctionDecl *initDecl) { auto selfDecl = cast(initDecl)->getImplicitSelfDecl(); - SmallVector cases; + SmallVector cases; for (auto elt : enumDecl->getAllElements()) { auto litExpr = cloneRawLiteralExpr(C, elt->getRawValueExpr()); auto litPat = new (C) ExprPattern(litExpr, /*isResolved*/ true, diff --git a/lib/Sema/GenericTypeResolver.h b/lib/Sema/GenericTypeResolver.h index 0c2147ba014..02b63fc24f8 100644 --- a/lib/Sema/GenericTypeResolver.h +++ b/lib/Sema/GenericTypeResolver.h @@ -36,16 +36,8 @@ class GenericTypeResolver { public: virtual ~GenericTypeResolver(); - /// Resolve the given generic type parameter to its type. - /// - /// This routine is used whenever type checking encounters a reference to a - /// generic parameter. It can replace the generic parameter with (for example) - /// a concrete type or an archetype, depending on context. - /// - /// \param gp The generic parameter to resolve. - /// - /// \returns The resolved generic type parameter type, which may be \c gp. - virtual Type resolveGenericTypeParamType(GenericTypeParamType *gp) = 0; + /// Resolve the given interface type to a contextual type if necessary. + virtual Type mapTypeIntoContext(Type type) = 0; /// Resolve a qualified reference to a type member within a dependent type. /// @@ -60,33 +52,6 @@ public: SourceRange baseRange, ComponentIdentTypeRepr *ref) = 0; - /// Resolve an unqualified reference to an associated type of the 'Self' type - /// of a protocol. - /// - /// \param selfTy The base of the member access. - /// \param assocType The associated type. - /// - /// \returns A type that refers to the dependent member type, or an error - /// type if such a reference is ill-formed. - virtual Type resolveSelfAssociatedType(Type selfTy, - AssociatedTypeDecl *assocType) = 0; - - /// Resolve the self type within the given context. - /// - /// \param dc A context in which type checking occurs, which must be a type - /// context (i.e., nominal type or extension thereof). - /// - /// \returns the type of context. - virtual Type resolveTypeOfContext(DeclContext *dc) = 0; - - /// Retrieve the type when referring to the given type declaration within - /// its context. - /// - /// \param decl A type declaration. - /// - /// \returns the type of the declaration in context.. - virtual Type resolveTypeOfDecl(TypeDecl *decl) = 0; - /// Determine whether the given types are equivalent within the generic /// context. virtual bool areSameType(Type type1, Type type2) = 0; @@ -101,20 +66,13 @@ public: /// and only trivially resolves dependent member types. class DependentGenericTypeResolver : public GenericTypeResolver { public: - virtual Type resolveGenericTypeParamType(GenericTypeParamType *gp); + virtual Type mapTypeIntoContext(Type type); virtual Type resolveDependentMemberType(Type baseTy, DeclContext *DC, SourceRange baseRange, ComponentIdentTypeRepr *ref); - virtual Type resolveSelfAssociatedType(Type selfTy, - AssociatedTypeDecl *assocType); - - virtual Type resolveTypeOfContext(DeclContext *dc); - - virtual Type resolveTypeOfDecl(TypeDecl *decl); - virtual bool areSameType(Type type1, Type type2); virtual void recordParamType(ParamDecl *decl, Type ty); @@ -135,19 +93,12 @@ public: explicit GenericTypeToArchetypeResolver(DeclContext *dc) : GenericEnv(dc->getGenericEnvironmentOfContext()) { } - virtual Type resolveGenericTypeParamType(GenericTypeParamType *gp); + virtual Type mapTypeIntoContext(Type type); virtual Type resolveDependentMemberType(Type baseTy, DeclContext *DC, SourceRange baseRange, ComponentIdentTypeRepr *ref); - virtual Type resolveSelfAssociatedType(Type selfTy, - AssociatedTypeDecl *assocType); - - virtual Type resolveTypeOfContext(DeclContext *dc); - - virtual Type resolveTypeOfDecl(TypeDecl *decl); - virtual bool areSameType(Type type1, Type type2); virtual void recordParamType(ParamDecl *decl, Type ty); @@ -159,25 +110,13 @@ public: /// This should only be used when resolving/validating where clauses in /// protocols. class ProtocolRequirementTypeResolver : public GenericTypeResolver { - ProtocolDecl *Proto; - public: - explicit ProtocolRequirementTypeResolver(ProtocolDecl *proto) - : Proto(proto) {} - - virtual Type resolveGenericTypeParamType(GenericTypeParamType *gp); + virtual Type mapTypeIntoContext(Type type); virtual Type resolveDependentMemberType(Type baseTy, DeclContext *DC, SourceRange baseRange, ComponentIdentTypeRepr *ref); - virtual Type resolveSelfAssociatedType(Type selfTy, - AssociatedTypeDecl *assocType); - - virtual Type resolveTypeOfContext(DeclContext *dc); - - virtual Type resolveTypeOfDecl(TypeDecl *decl); - virtual bool areSameType(Type type1, Type type2); virtual void recordParamType(ParamDecl *decl, Type ty); @@ -200,20 +139,13 @@ public: ArrayRef genericParams) : TC(tc), Builder(builder), GenericParams(genericParams) { } - virtual Type resolveGenericTypeParamType(GenericTypeParamType *gp); + virtual Type mapTypeIntoContext(Type type); virtual Type resolveDependentMemberType(Type baseTy, DeclContext *DC, SourceRange baseRange, ComponentIdentTypeRepr *ref); - virtual Type resolveSelfAssociatedType(Type selfTy, - AssociatedTypeDecl *assocType); - - virtual Type resolveTypeOfContext(DeclContext *dc); - - virtual Type resolveTypeOfDecl(TypeDecl *decl); - virtual bool areSameType(Type type1, Type type2); virtual void recordParamType(ParamDecl *decl, Type ty); diff --git a/lib/Sema/ITCDecl.cpp b/lib/Sema/ITCDecl.cpp index 4cbf1c13377..a24cbd6d685 100644 --- a/lib/Sema/ITCDecl.cpp +++ b/lib/Sema/ITCDecl.cpp @@ -108,15 +108,13 @@ void IterativeTypeChecker::processResolveInheritedClauseEntry( // Validate the type of this inherited clause entry. // FIXME: Recursion into existing type checker. - Optional protoResolver; - Optional archetypeResolver; + ProtocolRequirementTypeResolver protoResolver; + GenericTypeToArchetypeResolver archetypeResolver(dc); GenericTypeResolver *resolver; - if (auto *proto = dyn_cast(dc)) { - protoResolver.emplace(proto); - resolver = protoResolver.getPointer(); + if (isa(dc)) { + resolver = &protoResolver; } else { - archetypeResolver.emplace(dc); - resolver = archetypeResolver.getPointer(); + resolver = &archetypeResolver; } if (TC.validateType(*inherited, dc, options, resolver, diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index 59c8de63e95..12a86c2546c 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -210,7 +210,7 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E, } // Verify noescape parameter uses. - checkNoEscapeParameterUse(DRE, nullptr); + checkNoEscapeParameterUse(DRE, nullptr, OperandKind::None); // Verify warn_unqualified_access uses. checkUnqualifiedAccessUse(DRE); @@ -239,7 +239,7 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E, if (auto MakeEsc = dyn_cast(E)) { if (auto DRE = dyn_cast(MakeEsc->getNonescapingClosureValue())) - checkNoEscapeParameterUse(DRE, MakeEsc); + checkNoEscapeParameterUse(DRE, MakeEsc, OperandKind::MakeEscapable); } // Check function calls, looking through implicit conversions on the @@ -263,33 +263,11 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E, while (auto ignoredBase = dyn_cast(Base)) Base = ignoredBase->getRHS(); if (auto *DRE = dyn_cast(Base)) { - checkNoEscapeParameterUse(DRE, Call); + checkNoEscapeParameterUse(DRE, Call, OperandKind::Callee); checkForSuspiciousBitCasts(DRE, Call); } - auto *Arg = Call->getArg(); - - // The argument could be shuffled if it includes default arguments, - // label differences, or other exciting things like that. - if (auto *TSE = dyn_cast(Arg)) - Arg = TSE->getSubExpr(); - - // The argument is either a ParenExpr or TupleExpr. - ArrayRef arguments; - SmallVector Scratch; - if (auto *TE = dyn_cast(Arg)) - arguments = TE->getElements(); - else if (auto *PE = dyn_cast(Arg)) { - Scratch.push_back(PE->getSubExpr()); - arguments = makeArrayRef(Scratch); - } - else { - Scratch.push_back(Call->getArg()); - arguments = makeArrayRef(Scratch); - } - - // Check each argument. - for (auto arg : arguments) { + visitArguments(Call, [&](Expr *arg) { // InOutExpr's are allowed in argument lists directly. if (auto *IOE = dyn_cast(arg)) { if (isa(Call)) @@ -307,18 +285,12 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E, AcceptableInOutExprs.insert(IOE); } - while (1) { - if (auto conv = dyn_cast(arg)) - arg = conv->getSubExpr(); - else if (auto *PE = dyn_cast(arg)) - arg = PE->getSubExpr(); - else - break; - } + // Also give special treatment to noescape function arguments. + arg = lookThroughArgument(arg); if (auto *DRE = dyn_cast(arg)) - checkNoEscapeParameterUse(DRE, Call); - } + checkNoEscapeParameterUse(DRE, Call, OperandKind::Argument); + }); } // If we have an assignment expression, scout ahead for acceptable _'s. @@ -359,6 +331,38 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E, return { true, E }; } + static void visitArguments(ApplyExpr *apply, + llvm::function_ref fn) { + auto *arg = apply->getArg(); + + // The argument could be shuffled if it includes default arguments, + // label differences, or other exciting things like that. + if (auto *TSE = dyn_cast(arg)) + arg = TSE->getSubExpr(); + + // The argument is either a ParenExpr or TupleExpr. + if (auto *TE = dyn_cast(arg)) { + for (auto elt : TE->getElements()) + fn(elt); + } else if (auto *PE = dyn_cast(arg)) { + fn(PE->getSubExpr()); + } else { + fn(arg); + } + } + + static Expr *lookThroughArgument(Expr *arg) { + while (1) { + if (auto conv = dyn_cast(arg)) + arg = conv->getSubExpr(); + else if (auto *PE = dyn_cast(arg)) + arg = PE->getSubExpr(); + else + break; + } + return arg; + } + Expr *walkToExprPost(Expr *E) override { checkInvalidPartialApplication(E); return E; @@ -446,9 +450,118 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E, TC.diagnose(E->getStartLoc(), diag::value_of_module_type); } + class NoEscapeArgument { + llvm::PointerIntPair ParamAndIsCapture; + public: + NoEscapeArgument() {} + NoEscapeArgument(ParamDecl *param, bool isCapture) + : ParamAndIsCapture(param, isCapture) { + assert(param); + } + + explicit operator bool() const { + return ParamAndIsCapture.getPointer() != nullptr; + } + + ParamDecl *getDecl() const { return ParamAndIsCapture.getPointer(); } + bool isDeclACapture() const { return ParamAndIsCapture.getInt(); } + + static NoEscapeArgument find(TypeChecker &tc, ValueDecl *decl, + bool isCapture) { + if (auto param = dyn_cast(decl)) { + if (auto fnType = + param->getInterfaceType()->getAs()) { + if (fnType->isNoEscape()) + return { param, isCapture }; + } + return {}; + } + + if (auto fn = dyn_cast(decl)) { + if (fn->getDeclContext()->isLocalContext()) { + return findInCaptures(tc, fn); + } + return {}; + } + + // FIXME: captures of computed local vars? Can these be non-escaping? + return {}; + } + + static NoEscapeArgument findInCaptures(TypeChecker &tc, + AnyFunctionRef fn) { + // Ensure we have accurate capture information for the function. + tc.computeCaptures(fn); + + for (const auto &capture : fn.getCaptureInfo().getCaptures()) { + if (capture.isDynamicSelfMetadata()) continue; + if (auto param = find(tc, capture.getDecl(), true)) + return param; + } + return {}; + } + }; + + /// Enforce the exclusivity rule against calling a non-escaping + /// function parameter with another non-escaping function parameter + /// as an argument. + void checkNoEscapeParameterCall(ApplyExpr *apply) { + NoEscapeArgument noescapeArgument; + Expr *problematicArg = nullptr; + + visitArguments(apply, [&](Expr *arg) { + // Just find the first problematic argument. + if (noescapeArgument) return; + + // Remember the expression which used the argument. + problematicArg = arg; + + // Look through the same set of nodes that we look through when + // checking for no-escape functions. + arg = lookThroughArgument(arg); + + // If the argument isn't noescape, ignore it. + auto fnType = arg->getType()->getAs(); + if (!fnType || !fnType->isNoEscape()) + return; + + // Okay, it should be a closure or a decl ref. + if (auto declRef = dyn_cast(arg)) { + noescapeArgument = + NoEscapeArgument::find(TC, declRef->getDecl(), false); + } else if (auto closure = dyn_cast(arg)) { + noescapeArgument = + NoEscapeArgument::findInCaptures(TC, closure); + } else { + // This can happen with withoutActuallyEscaping. + assert(isa(arg) && + "unexpected expression yielding noescape closure"); + } + }); + + if (!noescapeArgument) return; + + // In Swift 3, this is just a warning. + TC.diagnose(apply->getLoc(), + TC.Context.isSwiftVersion3() + ? diag::warn_noescape_param_call + : diag::err_noescape_param_call, + noescapeArgument.getDecl()->getName(), + noescapeArgument.isDeclACapture()) + .highlight(problematicArg->getSourceRange()); + } + + enum class OperandKind { + None, + Callee, + Argument, + MakeEscapable, + }; + /// The DRE argument is a reference to a noescape parameter. Verify that /// its uses are ok. - void checkNoEscapeParameterUse(DeclRefExpr *DRE, Expr *ParentExpr=nullptr) { + void checkNoEscapeParameterUse(DeclRefExpr *DRE, Expr *parent, + OperandKind useKind) { // This only cares about declarations of noescape function type. auto AFT = DRE->getDecl()->getInterfaceType()->getAs(); if (!AFT || !AFT->isNoEscape()) @@ -463,10 +576,15 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E, // either as the callee or as an argument (in which case, the typechecker // validates that the noescape bit didn't get stripped off), or as // a special case, in the binding of a withoutActuallyEscaping block. - if (ParentExpr - && (isa(ParentExpr) // param() - || isa(ParentExpr))) - return; + if (parent) { + if (auto apply = dyn_cast(parent)) { + if (isa(DRE->getDecl()) && useKind == OperandKind::Callee) + checkNoEscapeParameterCall(apply); + return; + } else if (isa(parent)) { + return; + } + } TC.diagnose(DRE->getStartLoc(), diag::invalid_noescape_use, cast(DRE->getDecl())->getName(), @@ -474,16 +592,12 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E, // If we're a parameter, emit a helpful fixit to add @escaping auto paramDecl = dyn_cast(DRE->getDecl()); - auto isAutoClosure = AFT->isAutoClosure(); - if (paramDecl && !isAutoClosure) { + if (paramDecl) { TC.diagnose(paramDecl->getStartLoc(), diag::noescape_parameter, paramDecl->getName()) .fixItInsert(paramDecl->getTypeLoc().getSourceRange().Start, "@escaping "); - } else if (isAutoClosure) - // TODO: add in a fixit for autoclosure - TC.diagnose(DRE->getDecl()->getLoc(), diag::noescape_autoclosure, - paramDecl->getName()); + } } // Swift 3 mode produces a warning + Fix-It for the missing ".self" @@ -2005,6 +2119,11 @@ public: if (isa(D)) return false; + // The body of #if clauses are not walked into, we need custom processing + // for them. + if (auto *ICD = dyn_cast(D)) + handleIfConfig(ICD); + // If this is a VarDecl, then add it to our list of things to track. if (auto *vd = dyn_cast(D)) if (shouldTrackVarDecl(vd)) { @@ -2075,15 +2194,10 @@ public: std::pair walkToExprPre(Expr *E) override; /// handle #if directives. - void handleIfConfig(IfConfigStmt *ICS); + void handleIfConfig(IfConfigDecl *ICD); /// Custom handling for statements. std::pair walkToStmtPre(Stmt *S) override { - // The body of #if statements are not walked into, we need custom processing - // for them. - if (auto *ICS = dyn_cast(S)) - handleIfConfig(ICS); - // Keep track of an association between vardecls and the StmtCondition that // they are bound in for IfStmt, GuardStmt, WhileStmt, etc. if (auto LCS = dyn_cast(S)) { @@ -2365,6 +2479,17 @@ void VarDeclUsageChecker::markStoredOrInOutExpr(Expr *E, unsigned Flags) { return; } + // Likewise for key path applications. An application of a WritableKeyPath + // reads and writes its base. + if (auto *KPA = dyn_cast(E)) { + auto &C = KPA->getType()->getASTContext(); + KPA->getKeyPath()->walk(*this); + if (KPA->getKeyPath()->getType()->getAnyNominal() + == C.getWritableKeyPathDecl()) + markStoredOrInOutExpr(KPA->getBase(), RK_Written|RK_Read); + return; + } + if (auto *ioe = dyn_cast(E)) return markStoredOrInOutExpr(ioe->getSubExpr(), RK_Written|RK_Read); @@ -2440,7 +2565,7 @@ std::pair VarDeclUsageChecker::walkToExprPre(Expr *E) { /// handle #if directives. All of the active clauses are already walked by the /// AST walker, but we also want to handle the inactive ones to avoid false /// positives. -void VarDeclUsageChecker::handleIfConfig(IfConfigStmt *ICS) { +void VarDeclUsageChecker::handleIfConfig(IfConfigDecl *ICD) { struct ConservativeDeclMarker : public ASTWalker { VarDeclUsageChecker &VDUC; ConservativeDeclMarker(VarDeclUsageChecker &VDUC) : VDUC(VDUC) {} @@ -2455,7 +2580,7 @@ void VarDeclUsageChecker::handleIfConfig(IfConfigStmt *ICS) { } }; - for (auto &clause : ICS->getClauses()) { + for (auto &clause : ICD->getClauses()) { // Active clauses are handled by the normal AST walk. if (clause.isActive) continue; @@ -2514,7 +2639,7 @@ static Expr *endConditionValueForConvertingCStyleForLoop(const ForStmt *FS, return nullptr; // Verify that the condition is a simple != or < comparison to the loop variable. - auto comparisonOpName = binaryFuncExpr->getDecl()->getNameStr(); + auto comparisonOpName = binaryFuncExpr->getDecl()->getBaseName(); if (comparisonOpName == "!=") OpKind = OperatorKind::NotEqual; else if (comparisonOpName == "<") @@ -2556,7 +2681,7 @@ static bool unaryOperatorCheckForConvertingCStyleForLoop(const ForStmt *FS, auto unaryFuncExpr = dyn_cast(unaryExpr->getFn()); if (!unaryFuncExpr) return false; - if (unaryFuncExpr->getDecl()->getNameStr() != OpName) + if (unaryFuncExpr->getDecl()->getBaseName() != OpName) return false; return incrementDeclRefExpr->getDecl() == loopVar; } @@ -2585,7 +2710,7 @@ static bool binaryOperatorCheckForConvertingCStyleForLoop(TypeChecker &TC, auto binaryFuncExpr = dyn_cast(binaryExpr->getFn()); if (!binaryFuncExpr) return false; - if (binaryFuncExpr->getDecl()->getNameStr() != OpName) + if (binaryFuncExpr->getDecl()->getBaseName() != OpName) return false; auto argTupleExpr = dyn_cast(binaryExpr->getArg()); if (!argTupleExpr) diff --git a/lib/Sema/ResilienceDiagnostics.cpp b/lib/Sema/ResilienceDiagnostics.cpp index 53958cdb674..82890698e69 100644 --- a/lib/Sema/ResilienceDiagnostics.cpp +++ b/lib/Sema/ResilienceDiagnostics.cpp @@ -113,8 +113,25 @@ bool TypeChecker::diagnoseInlineableDeclRef(SourceLoc loc, D->getDescriptiveKind(), D->getFullName(), D->getFormalAccessScope().accessibilityForDiagnostics(), getFragileFunctionKind(DC)); - diagnose(D, diag::resilience_decl_declared_here, - D->getDescriptiveKind(), D->getFullName()); + + bool isDefaultArgument = false; + while (DC->isLocalContext()) { + if (isa(DC)) { + isDefaultArgument = true; + break; + } + + DC = DC->getParent(); + } + + if (isDefaultArgument) { + diagnose(D, diag::resilience_decl_declared_here, + D->getDescriptiveKind(), D->getFullName()); + } else { + diagnose(D, diag::resilience_decl_declared_here_versioned, + D->getDescriptiveKind(), D->getFullName()); + } + return true; } diff --git a/lib/Sema/Semantics.cpp b/lib/Sema/Semantics.cpp index f4cbf44b6e7..48a8865014f 100644 --- a/lib/Sema/Semantics.cpp +++ b/lib/Sema/Semantics.cpp @@ -14,6 +14,7 @@ #include "swift/AST/Expr.h" #include "swift/AST/Decl.h" #include "swift/AST/Stmt.h" +#include "swift/Syntax/Syntax.h" using namespace swift; using namespace swift::sema; diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp index 5d4553059f6..b26352acba7 100644 --- a/lib/Sema/TypeCheckAvailability.cpp +++ b/lib/Sema/TypeCheckAvailability.cpp @@ -2442,8 +2442,8 @@ bool AvailabilityWalker::diagnoseIncDecRemoval(const ValueDecl *D, SourceRange R, const AvailableAttr *Attr) { // We can only produce a fixit if we're talking about ++ or --. - bool isInc = D->getNameStr() == "++"; - if (!isInc && D->getNameStr() != "--") + bool isInc = D->getBaseName() == "++"; + if (!isInc && D->getBaseName() != "--") return false; // We can only handle the simple cases of lvalue++ and ++lvalue. This is @@ -2503,11 +2503,15 @@ bool AvailabilityWalker::diagnoseMemoryLayoutMigration(const ValueDecl *D, if (!D->getModuleContext()->isStdlibModule()) return false; - StringRef Property = llvm::StringSwitch(D->getNameStr()) - .Case("sizeof", "size") - .Case("alignof", "alignment") - .Case("strideof", "stride") - .Default(StringRef()); + StringRef Property; + if (D->getBaseName() == "sizeof") { + Property = "size"; + } else if (D->getBaseName() == "alignof") { + Property = "alignment"; + } else if (D->getBaseName() == "strideof") { + Property = "stride"; + } + if (Property.empty()) return false; diff --git a/lib/Sema/TypeCheckCaptures.cpp b/lib/Sema/TypeCheckCaptures.cpp index ccc9c912a2b..6d56eb9d368 100644 --- a/lib/Sema/TypeCheckCaptures.cpp +++ b/lib/Sema/TypeCheckCaptures.cpp @@ -211,17 +211,11 @@ public: // If we're a parameter, emit a helpful fixit to add @escaping auto paramDecl = dyn_cast(VD); - bool isAutoClosure = - VD->getInterfaceType()->castTo()->isAutoClosure(); - if (paramDecl && !isAutoClosure) { + if (paramDecl) { TC.diagnose(paramDecl->getStartLoc(), diag::noescape_parameter, paramDecl->getName()) .fixItInsert(paramDecl->getTypeLoc().getSourceRange().Start, "@escaping "); - } else if (isAutoClosure) { - // TODO: add in a fixit for autoclosure - TC.diagnose(VD->getLoc(), diag::noescape_autoclosure, - paramDecl->getName()); } } } @@ -362,7 +356,7 @@ public: isNested = f->getDeclContext()->isLocalContext(); if (isInOut && !AFR.isKnownNoEscape() && !isNested) { - if (D->getNameStr() == "self") { + if (D->getBaseName() == D->getASTContext().Id_self) { TC.diagnose(DRE->getLoc(), diag::closure_implicit_capture_mutating_self); } else { diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 410a0b34c0b..864e5a7246f 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -42,7 +42,6 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/Format.h" -#include "llvm/Support/Timer.h" #include #include #include @@ -498,12 +497,28 @@ resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC) { // FIXME: Need to refactor the way we build an AST node from a lookup result! + // If we have an unambiguous reference to a type decl, form a TypeExpr. + if (Lookup.size() == 1 && UDRE->getRefKind() == DeclRefKind::Ordinary && + isa(Lookup[0].Decl)) { + auto *D = cast(Lookup[0].Decl); + // FIXME: This is odd. + if (isa(D)) { + return new (Context) DeclRefExpr(D, UDRE->getNameLoc(), + /*Implicit=*/false, + AccessSemantics::Ordinary, + D->getInterfaceType()); + } + + return TypeExpr::createForDecl(Loc, D, + UDRE->isImplicit()); + } + bool AllDeclRefs = true; SmallVector ResultValues; for (auto Result : Lookup) { // If we find a member, then all of the results aren't non-members. bool IsMember = Result.Base && !isa(Result.Base); - if (IsMember && !isa(Result.Decl)) { + if (IsMember) { AllDeclRefs = false; break; } @@ -532,21 +547,6 @@ resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC) { if (matchesDeclRefKind(D, UDRE->getRefKind())) ResultValues.push_back(D); } - - // If we have an unambiguous reference to a type decl, form a TypeExpr. - if (ResultValues.size() == 1 && UDRE->getRefKind() == DeclRefKind::Ordinary && - isa(ResultValues[0])) { - // FIXME: This is odd. - if (isa(ResultValues[0])) { - return new (Context) DeclRefExpr(ResultValues[0], UDRE->getNameLoc(), - /*Implicit=*/false, - AccessSemantics::Ordinary, - ResultValues[0]->getInterfaceType()); - } - - return TypeExpr::createForDecl(Loc, cast(ResultValues[0]), - UDRE->isImplicit()); - } if (AllDeclRefs) { // Diagnose uses of operators that found no matching candidates. @@ -607,7 +607,11 @@ resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC) { if (AllMemberRefs) { Expr *BaseExpr; - if (auto NTD = dyn_cast(Base)) { + if (auto PD = dyn_cast(Base)) { + BaseExpr = TypeExpr::createForDecl(Loc, + PD->getGenericParams()->getParams().front(), + /*isImplicit=*/true); + } else if (auto NTD = dyn_cast(Base)) { BaseExpr = TypeExpr::createForDecl(Loc, NTD, /*isImplicit=*/true); } else { BaseExpr = new (Context) DeclRefExpr(Base, UDRE->getNameLoc(), @@ -1036,7 +1040,7 @@ TypeExpr *PreCheckExpression::simplifyNestedTypeExpr(UnresolvedDotExpr *UDE) { if (!UDE->getName().isSimpleName()) return nullptr; - auto Name = UDE->getName().getBaseName(); + auto Name = UDE->getName().getBaseIdentifier(); auto NameLoc = UDE->getNameLoc().getBaseNameLoc(); // Qualified type lookup with a module base is represented as a DeclRefExpr @@ -1211,12 +1215,13 @@ TypeExpr *PreCheckExpression::simplifyTypeExpr(Expr *E) { auto *TyExpr = dyn_cast(PE->getSubExpr()); if (!TyExpr) return nullptr; - TypeRepr *InnerTypeRepr[] = { TyExpr->getTypeRepr() }; - assert(!TyExpr->isImplicit() && InnerTypeRepr[0] && + TupleTypeReprElement InnerTypeRepr[] = { TyExpr->getTypeRepr() }; + assert(!TyExpr->isImplicit() && InnerTypeRepr[0].Type && "SubscriptExpr doesn't work on implicit TypeExpr's, " "the TypeExpr should have been built correctly in the first place"); - auto *NewTypeRepr = TupleTypeRepr::create(TC.Context, InnerTypeRepr, + auto *NewTypeRepr = TupleTypeRepr::create(TC.Context, + InnerTypeRepr, PE->getSourceRange()); return new (TC.Context) TypeExpr(TypeLoc(NewTypeRepr, Type())); } @@ -1228,35 +1233,29 @@ TypeExpr *PreCheckExpression::simplifyTypeExpr(Expr *E) { TE->getNumElements() == 0) return nullptr; - SmallVector Elts; - SmallVector EltNames; - SmallVector EltNameLocs; + SmallVector Elts; unsigned EltNo = 0; for (auto Elt : TE->getElements()) { auto *eltTE = dyn_cast(Elt); if (!eltTE) return nullptr; + TupleTypeReprElement elt; assert(eltTE->getTypeRepr() && !eltTE->isImplicit() && "This doesn't work on implicit TypeExpr's, the " "TypeExpr should have been built correctly in the first place"); // If the tuple element has a label, propagate it. - auto *eltTR = eltTE->getTypeRepr(); + elt.Type = eltTE->getTypeRepr(); Identifier name = TE->getElementName(EltNo); if (!name.empty()) { - if (EltNames.empty()) { - EltNames.resize(TE->getNumElements()); - EltNameLocs.resize(TE->getNumElements()); - } - EltNames[EltNo] = name; - EltNameLocs[EltNo] = TE->getElementNameLoc(EltNo); + elt.Name = name; + elt.NameLoc = TE->getElementNameLoc(EltNo); } - Elts.push_back(eltTR); - ++EltNo; + Elts.push_back(elt); + ++EltNo; } auto *NewTypeRepr = TupleTypeRepr::create(TC.Context, Elts, TE->getSourceRange(), - EltNames, EltNameLocs, {}, SourceLoc(), Elts.size()); return new (TC.Context) TypeExpr(TypeLoc(NewTypeRepr, Type())); } @@ -1304,13 +1303,13 @@ TypeExpr *PreCheckExpression::simplifyTypeExpr(Expr *E) { auto *TRE = dyn_cast_or_null(TE->getTypeRepr()); if (!TRE || TRE->getEllipsisLoc().isValid()) return nullptr; while (TRE->isParenType()) { - TRE = dyn_cast_or_null(TRE->getElement(0)); + TRE = dyn_cast_or_null(TRE->getElementType(0)); if (!TRE || TRE->getEllipsisLoc().isValid()) return nullptr; } assert(TRE->getElements().size() == 2); - keyTypeRepr = TRE->getElement(0); - valueTypeRepr = TRE->getElement(1); + keyTypeRepr = TRE->getElementType(0); + valueTypeRepr = TRE->getElementType(1); } auto *NewTypeRepr = @@ -1470,23 +1469,12 @@ void PreCheckExpression::resolveKeyPathExpr(KeyPathExpr *KPE) { expr = SE->getBase(); } else if (auto BOE = dyn_cast(expr)) { - if (!TC.Context.LangOpts.EnableExperimentalKeyPathComponents) { - TC.diagnose(BOE->getLoc(), - diag::expr_swift_keypath_unimplemented_component, - "optional chaining"); - } - // .? or ? components.push_back(KeyPathExpr::Component::forUnresolvedOptionalChain( BOE->getQuestionLoc())); expr = BOE->getSubExpr(); } else if (auto FVE = dyn_cast(expr)) { - if (!TC.Context.LangOpts.EnableExperimentalKeyPathComponents) { - TC.diagnose(FVE->getLoc(), - diag::expr_swift_keypath_unimplemented_component, - "optional force-unwrapping"); - } // .! or ! components.push_back(KeyPathExpr::Component::forUnresolvedOptionalForce( FVE->getExclaimLoc())); @@ -1772,41 +1760,6 @@ namespace { } } }; - - class ExpressionTimer { - Expr* E; - unsigned WarnLimit; - bool ShouldDump; - ASTContext &Context; - llvm::TimeRecord StartTime = llvm::TimeRecord::getCurrentTime(); - - public: - ExpressionTimer(Expr *E, bool shouldDump, unsigned warnLimit, - ASTContext &Context) - : E(E), WarnLimit(warnLimit), ShouldDump(shouldDump), Context(Context) { - } - - ~ExpressionTimer() { - llvm::TimeRecord endTime = llvm::TimeRecord::getCurrentTime(false); - - auto elapsed = endTime.getProcessTime() - StartTime.getProcessTime(); - unsigned elapsedMS = static_cast(elapsed * 1000); - - if (ShouldDump) { - // Round up to the nearest 100th of a millisecond. - llvm::errs() << llvm::format("%0.2f", ceil(elapsed * 100000) / 100) - << "ms\t"; - E->getLoc().print(llvm::errs(), Context.SourceMgr); - llvm::errs() << "\n"; - } - - if (WarnLimit != 0 && elapsedMS >= WarnLimit && E->getLoc().isValid()) - Context.Diags.diagnose(E->getLoc(), diag::debug_long_expression, - elapsedMS, WarnLimit) - .highlight(E->getSourceRange()); - } - }; - } // end anonymous namespace #pragma mark High-level entry points @@ -1816,11 +1769,6 @@ bool TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc, TypeCheckExprOptions options, ExprTypeCheckListener *listener, ConstraintSystem *baseCS) { - Optional timer; - if (DebugTimeExpressions || WarnLongExpressionTypeChecking) - timer.emplace(expr, DebugTimeExpressions, WarnLongExpressionTypeChecking, - Context); - PrettyStackTraceExpr stackTrace(Context, "type-checking", expr); // Construct a constraint system from this expression. @@ -2017,6 +1965,45 @@ getTypeOfExpressionWithoutApplying(Expr *&expr, DeclContext *dc, return exprType; } +void TypeChecker::getPossibleTypesOfExpressionWithoutApplying( + Expr *&expr, DeclContext *dc, SmallVectorImpl &types, + FreeTypeVariableBinding allowFreeTypeVariables, + ExprTypeCheckListener *listener) { + PrettyStackTraceExpr stackTrace(Context, "type-checking", expr); + + ExprCleaner cleaner(expr); + + // Construct a constraint system from this expression. + ConstraintSystemOptions options; + options |= ConstraintSystemFlags::AllowFixes; + options |= ConstraintSystemFlags::ReturnAllDiscoveredSolutions; + + ConstraintSystem cs(*this, dc, options); + + // Attempt to solve the constraint system. + SmallVector viable; + + // If the previous checking gives the expr error type, + // clear the result and re-check. + { + CleanupIllFormedExpressionRAII cleanup(Context, expr); + + const Type originalType = expr->getType(); + if (originalType && originalType->hasError()) + expr->setType(Type()); + + solveForExpression(expr, dc, /*convertType*/ Type(), allowFreeTypeVariables, + listener, cs, viable, + TypeCheckExprFlags::SuppressDiagnostics); + } + + for (auto &solution : viable) { + auto exprType = solution.simplifyType(cs.getType(expr)); + assert(exprType && !exprType->hasTypeVariable()); + types.push_back(exprType); + } +} + bool TypeChecker::typeCheckCompletionSequence(Expr *&expr, DeclContext *DC) { PrettyStackTraceExpr stackTrace(Context, "type-checking", expr); @@ -3117,6 +3104,19 @@ void Solution::dump(raw_ostream &out) const { out << "\n"; } } + + if (!Conformances.empty()) { + out << "\nConformances:\n"; + auto &cs = getConstraintSystem(); + for (auto &e : Conformances) { + out.indent(2); + out << "At "; + e.first->dump(&cs.getASTContext().SourceMgr, out); + out << "\n"; + e.second.dump(out); + out << "\n"; + } + } } void ConstraintSystem::dump() { diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 8e3587457e9..da653da95ab 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -243,7 +243,7 @@ void TypeChecker::resolveRawType(EnumDecl *enumDecl) { } void TypeChecker::validateWhereClauses(ProtocolDecl *protocol) { - ProtocolRequirementTypeResolver resolver(protocol); + ProtocolRequirementTypeResolver resolver; TypeResolutionOptions options; if (auto whereClause = protocol->getTrailingWhereClause()) { @@ -829,7 +829,7 @@ static bool isDefaultInitializable(TypeRepr *typeRepr) { return false; for (auto elt : tuple->getElements()) { - if (!isDefaultInitializable(elt)) + if (!isDefaultInitializable(elt.Type)) return false; } @@ -1245,12 +1245,14 @@ static void validatePatternBindingEntries(TypeChecker &tc, void swift::makeFinal(ASTContext &ctx, ValueDecl *D) { if (D && !D->isFinal()) { + assert(!D->isDynamic()); D->getAttrs().add(new (ctx) FinalAttr(/*IsImplicit=*/true)); } } void swift::makeDynamic(ASTContext &ctx, ValueDecl *D) { if (D && !D->isDynamic()) { + assert(!D->isFinal()); D->getAttrs().add(new (ctx) DynamicAttr(/*IsImplicit=*/true)); } } @@ -1751,11 +1753,12 @@ static void checkTypeAccessibility( AccessScope contextAccessScope = context->getFormalAccessScope(); checkTypeAccessibilityImpl(TC, TL, contextAccessScope, DC, - [=](AccessScope requiredAccessScope, - const TypeRepr *offendingTR, - DowngradeToWarning downgradeToWarning) { + [=, &TC](AccessScope requiredAccessScope, + const TypeRepr *offendingTR, + DowngradeToWarning downgradeToWarning) { if (!contextAccessScope.isPublic() && - !isa(contextAccessScope.getDeclContext())) { + !isa(contextAccessScope.getDeclContext()) && + TC.getLangOpts().isSwiftVersion3()) { // Swift 3.0.0 mistakenly didn't diagnose any issues when the context // access scope represented a private or fileprivate level. downgradeToWarning = DowngradeToWarning::Yes; @@ -1868,10 +1871,10 @@ static void checkGenericParamAccessibility(TypeChecker &TC, // Swift 3.0.0 mistakenly didn't diagnose any issues when the context access // scope represented a private or fileprivate level. - // FIXME: Conditionalize this on Swift 3 mode. if (downgradeToWarning == DowngradeToWarning::No) { if (!accessScope.isPublic() && - !isa(accessScope.getDeclContext())) { + !isa(accessScope.getDeclContext()) && + TC.getLangOpts().isSwiftVersion3()) { downgradeToWarning = DowngradeToWarning::Yes; } } @@ -2555,15 +2558,29 @@ static void inferDynamic(ASTContext &ctx, ValueDecl *D) { // Variables declared with 'let' cannot be 'dynamic'. if (auto VD = dyn_cast(D)) { - if (VD->isLet() && !isNSManaged) return; + auto staticSpelling = VD->getParentPatternBinding()->getStaticSpelling(); + + // The presence of 'static' blocks the inference of 'dynamic'. + if (staticSpelling == StaticSpellingKind::KeywordStatic) + return; + + if (VD->isLet() && !isNSManaged) + return; } // Accessors should not infer 'dynamic' on their own; they can get it from // their storage decls. - if (auto FD = dyn_cast(D)) + if (auto FD = dyn_cast(D)) { if (FD->isAccessor()) return; + auto staticSpelling = FD->getStaticSpelling(); + + // The presence of 'static' bocks the inference of 'dynamic'. + if (staticSpelling == StaticSpellingKind::KeywordStatic) + return; + } + // The presence of 'final' on a class prevents 'dynamic'. auto classDecl = D->getDeclContext()->getAsClassOrClassExtensionContext(); if (!classDecl) return; @@ -3882,9 +3899,10 @@ public: VD->getNameLoc().isValid() && Context.SourceMgr.extractText({VD->getNameLoc(), 1}) != "`") { TC.diagnose(VD->getNameLoc(), diag::reserved_member_name, - VD->getFullName(), VD->getNameStr()); + VD->getFullName(), VD->getBaseName().getIdentifier().str()); TC.diagnose(VD->getNameLoc(), diag::backticks_to_escape) - .fixItReplace(VD->getNameLoc(), "`"+VD->getNameStr().str()+"`"); + .fixItReplace(VD->getNameLoc(), + "`" + VD->getBaseName().userFacingName().str() + "`"); } } @@ -4913,7 +4931,7 @@ public: // Look through parentheses. if (auto parenRepr = dyn_cast(typeRepr)) { if (!parenRepr->isParenType()) return false; - return checkDynamicSelfReturn(func, parenRepr->getElement(0), + return checkDynamicSelfReturn(func, parenRepr->getElementType(0), optionalDepth); } @@ -5037,6 +5055,12 @@ public: else if (FD->getAttrs().hasAttribute()) FD->setMutating(false); + if (FD->isMutating()) { + Type contextTy = FD->getDeclContext()->getDeclaredInterfaceType(); + if (contextTy->hasReferenceSemantics()) + FD->setMutating(false); + } + // Check whether the return type is dynamic 'Self'. if (checkDynamicSelfReturn(FD)) FD->setInvalid(); @@ -5169,8 +5193,7 @@ public: // If the storage is dynamic or final, propagate to this accessor. if (isObjC && - storage->isDynamic() && - !storage->isFinal()) + storage->isDynamic()) makeDynamic(TC.Context, FD); if (storage->isFinal()) @@ -7054,6 +7077,27 @@ static Optional shouldMarkClassAsObjC(TypeChecker &TC, return None; } +/// Validate the underlying type of the given typealias. +static void validateTypealiasType(TypeChecker &tc, TypeAliasDecl *typeAlias) { + TypeResolutionOptions options = TR_TypeAliasUnderlyingType; + if (typeAlias->getFormalAccess() <= Accessibility::FilePrivate) + options |= TR_KnownNonCascadingDependency; + + if (typeAlias->getDeclContext()->isModuleScopeContext() && + typeAlias->getGenericParams() == nullptr) { + IterativeTypeChecker ITC(tc); + ITC.satisfy(requestResolveTypeDecl(typeAlias)); + } else { + if (tc.validateType(typeAlias->getUnderlyingTypeLoc(), + typeAlias, options)) { + typeAlias->setInvalid(); + typeAlias->getUnderlyingTypeLoc().setInvalidType(tc.Context); + } + + typeAlias->setUnderlyingType(typeAlias->getUnderlyingTypeLoc().getType()); + } +} + void TypeChecker::validateDecl(ValueDecl *D) { // Generic parameters are validated as part of their context. if (isa(D)) @@ -7161,25 +7205,7 @@ void TypeChecker::validateDecl(ValueDecl *D) { SWIFT_DEFER { typeAlias->setIsBeingValidated(false); }; validateGenericTypeSignature(typeAlias); - - TypeResolutionOptions options = TR_TypeAliasUnderlyingType; - if (typeAlias->getFormalAccess() <= Accessibility::FilePrivate) - options |= TR_KnownNonCascadingDependency; - - if (typeAlias->getDeclContext()->isModuleScopeContext() && - typeAlias->getGenericParams() == nullptr) { - IterativeTypeChecker ITC(*this); - ITC.satisfy(requestResolveTypeDecl(typeAlias)); - } else { - if (validateType(typeAlias->getUnderlyingTypeLoc(), - typeAlias, options)) { - typeAlias->setInvalid(); - typeAlias->getUnderlyingTypeLoc().setInvalidType(Context); - } - - typeAlias->setUnderlyingType(typeAlias->getUnderlyingTypeLoc().getType()); - } - + validateTypealiasType(*this, typeAlias); break; } @@ -7246,8 +7272,28 @@ void TypeChecker::validateDecl(ValueDecl *D) { // FIXME: Hopefully this can all go away with the ITC. for (auto member : proto->getMembers()) { if (auto *aliasDecl = dyn_cast(member)) { - if (!aliasDecl->isGeneric()) + if (!aliasDecl->isGeneric()) { aliasDecl->setGenericEnvironment(proto->getGenericEnvironment()); + + // If the underlying alias declaration has a type parameter, + // we have unresolved dependent member types we will need to deal + // with. Wipe out the types and validate them again. + // FIXME: We never should have recorded such a type in the first + // place. + if (!aliasDecl->getUnderlyingTypeLoc().getType() || + aliasDecl->getUnderlyingTypeLoc().getType() + ->findUnresolvedDependentMemberType()) { + aliasDecl->getUnderlyingTypeLoc().setType(Type(), + /*validated=*/false); + validateAccessibility(aliasDecl); + + // Check generic parameters, if needed. + aliasDecl->setIsBeingValidated(); + SWIFT_DEFER { aliasDecl->setIsBeingValidated(false); }; + + validateTypealiasType(*this, aliasDecl); + } + } } } @@ -7497,9 +7543,9 @@ void TypeChecker::validateDeclForNameLookup(ValueDecl *D) { return; // Perform earlier validation of typealiases in protocols. - if (auto proto = dyn_cast(dc)) { + if (isa(dc)) { if (!typealias->getGenericParams()) { - ProtocolRequirementTypeResolver resolver(proto); + ProtocolRequirementTypeResolver resolver; TypeResolutionOptions options; if (typealias->isBeingValidated()) return; @@ -7683,7 +7729,8 @@ checkExtensionGenericParams(TypeChecker &tc, ExtensionDecl *ext, Type type, // Local function used to infer requirements from the extended type. auto inferExtendedTypeReqs = [&](GenericSignatureBuilder &builder) { auto source = - GenericSignatureBuilder::FloatingRequirementSource::forInferred(nullptr); + GenericSignatureBuilder::FloatingRequirementSource::forInferred( + nullptr, /*quietly=*/false); builder.inferRequirements(*ext->getModuleContext(), TypeLoc::withoutLoc(extInterfaceType), @@ -7777,18 +7824,6 @@ void TypeChecker::validateExtension(ExtensionDecl *ext) { // FIXME: Probably the above comes up elsewhere, perhaps getAs<>() // should be fixed. if (auto proto = extendedType->getCanonicalType()->getAs()) { - if (!isa(extendedType.getPointer()) && - proto->getDecl()->getParentModule() == ext->getParentModule()) { - // Protocols in the same module cannot be extended via a typealias; - // we could end up being unable to resolve the generic signature. - diagnose(ext->getLoc(), diag::extension_protocol_via_typealias, proto) - .fixItReplace(ext->getExtendedTypeLoc().getSourceRange(), - proto->getDecl()->getName().str()); - ext->setInvalid(); - ext->getExtendedTypeLoc().setInvalidType(Context); - return; - } - GenericEnvironment *env; std::tie(env, extendedType) = checkExtensionGenericParams(*this, ext, proto, ext->getGenericParams()); diff --git a/lib/Sema/TypeCheckError.cpp b/lib/Sema/TypeCheckError.cpp index aaa82a231a0..4271e0f3820 100644 --- a/lib/Sema/TypeCheckError.cpp +++ b/lib/Sema/TypeCheckError.cpp @@ -192,9 +192,14 @@ class ErrorHandlingWalker : public ASTWalker { Impl &asImpl() { return *static_cast(this); } public: bool walkToDeclPre(Decl *D) override { + ShouldRecurse_t recurse = ShouldRecurse; // Skip the implementations of all local declarations... except // PBD. We should really just have a PatternBindingStmt. - return isa(D); + if (auto ic = dyn_cast(D)) + recurse = asImpl().checkIfConfig(ic); + else if (!isa(D)) + recurse = ShouldNotRecurse; + return bool(recurse); } std::pair walkToExprPre(Expr *E) override { @@ -230,8 +235,6 @@ public: recurse = asImpl().checkDoCatch(doCatch); } else if (auto thr = dyn_cast(S)) { recurse = asImpl().checkThrow(thr); - } else if (auto ic = dyn_cast(S)) { - recurse = asImpl().checkIfConfig(ic); } else { assert(!isa(S)); } @@ -606,7 +609,7 @@ private: return ShouldRecurse; } - ShouldRecurse_t checkIfConfig(IfConfigStmt *S) { + ShouldRecurse_t checkIfConfig(IfConfigDecl *D) { return ShouldRecurse; } @@ -1431,7 +1434,7 @@ private: return !type || type->hasError() ? ShouldNotRecurse : ShouldRecurse; } - ShouldRecurse_t checkIfConfig(IfConfigStmt *S) { + ShouldRecurse_t checkIfConfig(IfConfigDecl *ICD) { // Check the inactive regions of a #if block to disable warnings that may // be due to platform specific code. struct ConservativeThrowChecker : public ASTWalker { @@ -1452,7 +1455,7 @@ private: } }; - for (auto &clause : S->getClauses()) { + for (auto &clause : ICD->getClauses()) { // Active clauses are handled by the normal AST walk. if (clause.isActive) continue; diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index 7d76f182e2e..193bb411df9 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -29,12 +29,8 @@ using namespace swift; /// GenericTypeResolver implementations /// -Type DependentGenericTypeResolver::resolveGenericTypeParamType( - GenericTypeParamType *gp) { - assert(gp->getDecl() && "Missing generic parameter declaration"); - - // Don't resolve generic parameters. - return gp; +Type DependentGenericTypeResolver::mapTypeIntoContext(Type type) { + return type; } Type DependentGenericTypeResolver::resolveDependentMemberType( @@ -45,19 +41,6 @@ Type DependentGenericTypeResolver::resolveDependentMemberType( return DependentMemberType::get(baseTy, ref->getIdentifier()); } -Type DependentGenericTypeResolver::resolveSelfAssociatedType( - Type selfTy, AssociatedTypeDecl *assocType) { - return DependentMemberType::get(selfTy, assocType); -} - -Type DependentGenericTypeResolver::resolveTypeOfContext(DeclContext *dc) { - return dc->getSelfInterfaceType(); -} - -Type DependentGenericTypeResolver::resolveTypeOfDecl(TypeDecl *decl) { - return decl->getDeclaredInterfaceType(); -} - bool DependentGenericTypeResolver::areSameType(Type type1, Type type2) { if (!type1->hasTypeParameter() && !type2->hasTypeParameter()) return type1->isEqual(type2); @@ -70,9 +53,8 @@ void DependentGenericTypeResolver::recordParamType(ParamDecl *decl, Type type) { // Do nothing } -Type GenericTypeToArchetypeResolver::resolveGenericTypeParamType( - GenericTypeParamType *gp) { - return GenericEnv->mapTypeIntoContext(gp); +Type GenericTypeToArchetypeResolver::mapTypeIntoContext(Type type) { + return GenericEnvironment::mapTypeIntoContext(GenericEnv, type); } Type GenericTypeToArchetypeResolver::resolveDependentMemberType( @@ -83,21 +65,6 @@ Type GenericTypeToArchetypeResolver::resolveDependentMemberType( llvm_unreachable("Dependent type after archetype substitution"); } -Type GenericTypeToArchetypeResolver::resolveSelfAssociatedType( - Type selfTy, AssociatedTypeDecl *assocType) { - llvm_unreachable("Dependent type after archetype substitution"); -} - -Type GenericTypeToArchetypeResolver::resolveTypeOfContext(DeclContext *dc) { - return GenericEnvironment::mapTypeIntoContext( - GenericEnv, dc->getSelfInterfaceType()); -} - -Type GenericTypeToArchetypeResolver::resolveTypeOfDecl(TypeDecl *decl) { - return GenericEnvironment::mapTypeIntoContext( - GenericEnv, decl->getDeclaredInterfaceType()); -} - bool GenericTypeToArchetypeResolver::areSameType(Type type1, Type type2) { return type1->isEqual(type2); } @@ -116,11 +83,8 @@ void GenericTypeToArchetypeResolver::recordParamType(ParamDecl *decl, Type type) GenericEnv, type)); } -Type ProtocolRequirementTypeResolver::resolveGenericTypeParamType( - GenericTypeParamType *gp) { - assert(gp->isEqual(Proto->getSelfInterfaceType()) && - "found non-Self-shaped GTPT when resolving protocol requirement"); - return gp; +Type ProtocolRequirementTypeResolver::mapTypeIntoContext(Type type) { + return type; } Type ProtocolRequirementTypeResolver::resolveDependentMemberType( @@ -129,21 +93,6 @@ Type ProtocolRequirementTypeResolver::resolveDependentMemberType( return DependentMemberType::get(baseTy, ref->getIdentifier()); } -Type ProtocolRequirementTypeResolver::resolveSelfAssociatedType( - Type selfTy, AssociatedTypeDecl *assocType) { - assert(selfTy->isEqual(Proto->getSelfInterfaceType())); - (void)Proto; - return assocType->getDeclaredInterfaceType(); -} - -Type ProtocolRequirementTypeResolver::resolveTypeOfContext(DeclContext *dc) { - return dc->getSelfInterfaceType(); -} - -Type ProtocolRequirementTypeResolver::resolveTypeOfDecl(TypeDecl *decl) { - return decl->getDeclaredInterfaceType(); -} - bool ProtocolRequirementTypeResolver::areSameType(Type type1, Type type2) { if (type1->isEqual(type2)) return true; @@ -167,13 +116,10 @@ void ProtocolRequirementTypeResolver::recordParamType(ParamDecl *decl, "recording a param type of a protocol requirement doesn't make sense"); } -Type CompleteGenericTypeResolver::resolveGenericTypeParamType( - GenericTypeParamType *gp) { - assert(gp->getDecl() && "Missing generic parameter declaration"); - return gp; +Type CompleteGenericTypeResolver::mapTypeIntoContext(Type type) { + return type; } - Type CompleteGenericTypeResolver::resolveDependentMemberType( Type baseTy, DeclContext *DC, @@ -185,8 +131,22 @@ Type CompleteGenericTypeResolver::resolveDependentMemberType( ArchetypeResolutionKind::CompleteWellFormed); assert(basePA && "Missing potential archetype for base"); + // Local function to produce an error "no such member type" and return. + auto invalidMemberType = [&] { + // Complain that there is no suitable type. + Identifier name = ref->getIdentifier(); + SourceLoc nameLoc = ref->getIdLoc(); + TC.diagnose(nameLoc, diag::invalid_member_type, name, baseTy) + .highlight(baseRange); + return ErrorType::get(TC.Context); + }; + // Retrieve the potential archetype for the nested type. - auto nestedPA = basePA->getNestedType(ref->getIdentifier(), Builder); + auto nestedPA = basePA->getNestedType(ref->getIdentifier(), + ArchetypeResolutionKind::WellFormed, + Builder); + if (!nestedPA) + return invalidMemberType(); // If this potential archetype was renamed due to typo correction, // complain and fix it. @@ -199,7 +159,10 @@ Type CompleteGenericTypeResolver::resolveDependentMemberType( nestedPA->setAlreadyDiagnosedRename(); // Go get the actual nested type. - nestedPA = basePA->getNestedType(newName, Builder); + nestedPA = basePA->getNestedType(newName, + ArchetypeResolutionKind::WellFormed, + Builder); + assert(nestedPA && "Nested type should have been available"); assert(!nestedPA->wasRenamed()); } @@ -218,6 +181,7 @@ Type CompleteGenericTypeResolver::resolveDependentMemberType( if (auto proto = concrete->getDeclContext() ->getAsProtocolOrProtocolExtensionContext()) { + TC.validateDecl(proto); auto subMap = SubstitutionMap::getProtocolSubstitutions( proto, baseTy, ProtocolConformanceRef(proto)); return concrete->getDeclaredInterfaceType().subst(subMap); @@ -236,29 +200,7 @@ Type CompleteGenericTypeResolver::resolveDependentMemberType( } assert(nestedPA->isUnresolved() && "meaningless unresolved type"); - - // Complain that there is no suitable type. - Identifier name = ref->getIdentifier(); - SourceLoc nameLoc = ref->getIdLoc(); - TC.diagnose(nameLoc, diag::invalid_member_type, name, baseTy) - .highlight(baseRange); - return ErrorType::get(TC.Context); -} - -Type CompleteGenericTypeResolver::resolveSelfAssociatedType( - Type selfTy, AssociatedTypeDecl *assocType) { - return Builder.resolveArchetype(selfTy, - ArchetypeResolutionKind::CompleteWellFormed) - ->getNestedType(assocType, Builder) - ->getDependentType(GenericParams, /*allowUnresolved=*/false); -} - -Type CompleteGenericTypeResolver::resolveTypeOfContext(DeclContext *dc) { - return dc->getSelfInterfaceType(); -} - -Type CompleteGenericTypeResolver::resolveTypeOfDecl(TypeDecl *decl) { - return decl->getDeclaredInterfaceType(); + return invalidMemberType(); } bool CompleteGenericTypeResolver::areSameType(Type type1, Type type2) { @@ -523,7 +465,8 @@ static bool checkGenericFuncSignature(TypeChecker &tc, fn->getBodyResultTypeLoc().getTypeRepr()) { auto source = GenericSignatureBuilder::FloatingRequirementSource::forInferred( - fn->getBodyResultTypeLoc().getTypeRepr()); + fn->getBodyResultTypeLoc().getTypeRepr(), + /*quietly=*/true); builder->inferRequirements(*func->getParentModule(), fn->getBodyResultTypeLoc(), source); @@ -965,7 +908,8 @@ static bool checkGenericSubscriptSignature(TypeChecker &tc, if (genericParams && builder) { auto source = GenericSignatureBuilder::FloatingRequirementSource::forInferred( - subscript->getElementTypeLoc().getTypeRepr()); + subscript->getElementTypeLoc().getTypeRepr(), + /*quietly=*/true); builder->inferRequirements(*subscript->getParentModule(), subscript->getElementTypeLoc(), @@ -980,9 +924,10 @@ static bool checkGenericSubscriptSignature(TypeChecker &tc, resolver); // Infer requirements from the pattern. - if (builder) + if (builder) { builder->inferRequirements(*subscript->getParentModule(), params, genericParams); + } return badType; } diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp index d0190a4b9a5..7dfa0845435 100644 --- a/lib/Sema/TypeCheckNameLookup.cpp +++ b/lib/Sema/TypeCheckNameLookup.cpp @@ -187,24 +187,19 @@ LookupResult TypeChecker::lookupUnqualified(DeclContext *dc, DeclName name, for (const auto &found : lookup.Results) { // Determine which type we looked through to find this result. Type foundInType; + if (!found.getBaseDecl()) { // Not found within a type. - } else if (auto baseParam = dyn_cast(found.getBaseDecl())) { - auto baseDC = baseParam->getDeclContext(); - if (isa(baseDC)) - baseDC = baseDC->getParent(); - if (isa(baseDC)) - baseDC = baseDC->getParent(); - foundInType = baseDC->getDeclaredTypeInContext(); - assert(foundInType && "bogus base declaration?"); } else { - auto baseNominal = cast(found.getBaseDecl()); - for (auto currentDC = dc; currentDC; currentDC = currentDC->getParent()) { - if (currentDC->getAsNominalTypeOrNominalTypeExtensionContext() - == baseNominal) { - foundInType = currentDC->getDeclaredTypeInContext(); - } + DeclContext *baseDC = nullptr; + if (auto baseParam = dyn_cast(found.getBaseDecl())) { + baseDC = baseParam->getDeclContext()->getParent(); + } else { + baseDC = cast(found.getBaseDecl()); } + + foundInType = dc->mapTypeIntoContext( + baseDC->getDeclaredInterfaceType()); assert(foundInType && "bogus base declaration?"); } diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 489e10142bd..e8336d26f24 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -517,24 +517,6 @@ namespace { }; } // end anonymous namespace -///\ brief Decompose the given type into a set of tuple elements. -static SmallVector decomposeIntoTupleElements(Type type) { - SmallVector result; - - if (auto tupleTy = dyn_cast(type.getPointer())) { - result.append(tupleTy->getElements().begin(), tupleTy->getElements().end()); - return result; - } - - if (auto parenTy = dyn_cast(type.getPointer())) { - result.push_back(parenTy->getUnderlyingType()); - return result; - } - - result.push_back(type); - return result; -} - /// If the given type is a direct reference to an associated type of /// the given protocol, return the referenced associated type. static AssociatedTypeDecl * @@ -919,10 +901,8 @@ matchWitness(TypeChecker &tc, if (decomposeFunctionType) { // Decompose function types into parameters and result type. auto reqFnType = reqType->castTo(); - auto reqInputType = reqFnType->getInput(); auto reqResultType = reqFnType->getResult()->getRValueType(); auto witnessFnType = witnessType->castTo(); - auto witnessInputType = witnessFnType->getInput(); auto witnessResultType = witnessFnType->getResult()->getRValueType(); // Result types must match. @@ -947,8 +927,8 @@ matchWitness(TypeChecker &tc, // Parameter types and kinds must match. Start by decomposing the input // types into sets of tuple elements. // Decompose the input types into parameters. - auto reqParams = decomposeIntoTupleElements(reqInputType); - auto witnessParams = decomposeIntoTupleElements(witnessInputType); + auto reqParams = reqFnType->getParams(); + auto witnessParams = witnessFnType->getParams(); // If the number of parameters doesn't match, we're done. if (reqParams.size() != witnessParams.size()) @@ -959,7 +939,7 @@ matchWitness(TypeChecker &tc, for (unsigned i = 0, n = reqParams.size(); i != n; ++i) { // Variadic bits must match. // FIXME: Specialize the match failure kind - if (reqParams[i].isVararg() != witnessParams[i].isVararg()) + if (reqParams[i].isVariadic() != witnessParams[i].isVariadic()) return RequirementMatch(witness, MatchKind::TypeConflict, witnessType); // Gross hack: strip a level of unchecked-optionality off both @@ -1391,7 +1371,7 @@ bool WitnessChecker::findBestWitness( auto lookupOptions = defaultUnqualifiedLookupOptions; lookupOptions |= NameLookupFlags::KnownPrivate; - auto lookup = TC.lookupUnqualified(overlay, requirement->getName(), + auto lookup = TC.lookupUnqualified(overlay, requirement->getBaseName(), SourceLoc(), lookupOptions); for (auto candidate : lookup) witnesses.push_back(candidate.Decl); @@ -2654,7 +2634,7 @@ printRequirementStub(ValueDecl *Requirement, DeclContext *Adopter, Options.PrintDocumentationComments = false; Options.AccessibilityFilter = Accessibility::Private; Options.PrintAccessibility = false; - Options.ExcludeAttrList.push_back(DAK_Available); + Options.SkipAttributes = true; Options.FunctionBody = [](const ValueDecl *VD) { return getCodePlaceholder(); }; Options.setBaseType(AdopterTy); Options.CurrentModule = Adopter->getParentModule(); @@ -3122,9 +3102,7 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) { auto proto = Conformance->getProtocol(); auto &diags = proto->getASTContext().Diags; diags.diagnose(witness->getLoc(), - proto->getASTContext().LangOpts.isSwiftVersion3() - ? diag::witness_self_same_type_warn - : diag::witness_self_same_type, + diag::witness_self_same_type, witness->getDescriptiveKind(), witness->getFullName(), Conformance->getType(), @@ -3291,17 +3269,17 @@ static CheckTypeWitnessResult checkTypeWitness(TypeChecker &tc, DeclContext *dc, AssociatedTypeDecl *assocType, Type type) { auto *moduleDecl = dc->getParentModule(); - auto *reqtSig = assocType->getProtocol()->getRequirementSignature(); + auto *genericSig = proto->getGenericSignature(); auto *depTy = DependentMemberType::get(proto->getSelfInterfaceType(), assocType); - if (auto superclass = reqtSig->getSuperclassBound(depTy, *moduleDecl)) { + if (auto superclass = genericSig->getSuperclassBound(depTy, *moduleDecl)) { if (!superclass->isExactSuperclassOf(type)) return superclass->getAnyNominal(); } // Check protocol conformances. - for (auto reqProto : reqtSig->getConformsTo(depTy, *moduleDecl)) { + for (auto reqProto : genericSig->getConformsTo(depTy, *moduleDecl)) { if (!tc.conformsToProtocol(type, reqProto, dc, None)) return reqProto; @@ -5471,20 +5449,8 @@ Optional TypeChecker::conformsToProtocol( } // If we're using this conformance, note that. - if (options.contains(ConformanceCheckFlags::Used) && - lookupResult->isConcrete()) { - auto concrete = lookupResult->getConcrete(); - auto normalConf = concrete->getRootNormalConformance(); - - // If the conformance is incomplete, queue it for completion. - if (normalConf->isIncomplete()) - UsedConformances.insert(normalConf); - - // Record the usage of this conformance in the enclosing source - // file. - if (auto sf = DC->getParentSourceFile()) { - sf->addUsedConformance(normalConf); - } + if (options.contains(ConformanceCheckFlags::Used)) { + markConformanceUsed(*lookupResult, DC); } // When requested, print the conformance access path used to find this @@ -5547,6 +5513,24 @@ TypeChecker::conformsToProtocol(Type T, ProtocolDecl *Proto, DeclContext *DC, : ConformsToProtocolResult::failure(); } +void TypeChecker::markConformanceUsed(ProtocolConformanceRef conformance, + DeclContext *dc) { + if (conformance.isAbstract()) return; + + auto normalConformance = + conformance.getConcrete()->getRootNormalConformance(); + + // Make sure that the type checker completes this conformance. + if (normalConformance->isIncomplete()) + UsedConformances.insert(normalConformance); + + // Record the usage of this conformance in the enclosing source + // file. + if (auto sf = dc->getParentSourceFile()) { + sf->addUsedConformance(normalConformance); + } +} + Optional TypeChecker::LookUpConformance::operator()( CanType dependentType, diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 3c1d8886a4c..60633a6a232 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -512,14 +512,6 @@ public: return GS; } - Stmt *visitIfConfigStmt(IfConfigStmt *ICS) { - - // Active members are attached to the enclosing declaration, so there's no - // need to walk anything within. - - return ICS; - } - Stmt *visitDoStmt(DoStmt *DS) { AddLabeledStmt loopNest(*this, DS); Stmt *S = DS->getBody(); @@ -871,11 +863,12 @@ public: AddSwitchNest switchNest(*this); AddLabeledStmt labelNest(*this, S); - for (unsigned i = 0, e = S->getCases().size(); i < e; ++i) { - auto *caseBlock = S->getCases()[i]; + auto cases = S->getCases(); + for (auto i = cases.begin(), e = cases.end(); i != e; ++i) { + auto *caseBlock = *i; // Fallthrough transfers control to the next case block. In the // final case block, it is invalid. - FallthroughDest = i+1 == e ? nullptr : S->getCases()[i+1]; + FallthroughDest = std::next(i) == e ? nullptr : *std::next(i); for (auto &labelItem : caseBlock->getMutableCaseLabelItems()) { // Resolve the pattern in the label. diff --git a/lib/Sema/TypeCheckSwitchStmt.cpp b/lib/Sema/TypeCheckSwitchStmt.cpp index d5594cad23a..30d880f36b5 100644 --- a/lib/Sema/TypeCheckSwitchStmt.cpp +++ b/lib/Sema/TypeCheckSwitchStmt.cpp @@ -76,6 +76,9 @@ namespace { private: SpaceKind Kind; llvm::PointerIntPair TypeAndVal; + + // In type space, we reuse HEAD to help us print meaningful name, e.g., + // tuple element name in fixits. Identifier Head; std::forward_list Spaces; @@ -134,8 +137,8 @@ namespace { } public: - explicit Space(Type T) - : Kind(SpaceKind::Type), TypeAndVal(T, false), Head(Identifier()), + explicit Space(Type T, Identifier NameForPrinting) + : Kind(SpaceKind::Type), TypeAndVal(T, false), Head(NameForPrinting), Spaces({}){} explicit Space(Type T, Identifier H, bool downgrade, SmallVectorImpl &SP) @@ -189,6 +192,12 @@ namespace { return Head; } + Identifier getPrintingName() const { + assert(getKind() == SpaceKind::Type + && "Wrong kind of space tried to access printing name"); + return Head; + } + const std::forward_list &getSpaces() const { assert((getKind() == SpaceKind::Constructor || getKind() == SpaceKind::Disjunct) @@ -750,7 +759,11 @@ namespace { if (!forDisplay) { getType()->print(buffer); } - buffer << "_"; + Identifier Name = getPrintingName(); + if (Name.empty()) + buffer << "_"; + else + buffer << tok::kw_let << " " << Name.str(); break; } } @@ -865,10 +878,11 @@ namespace { TTy->getElements().end(), std::back_inserter(constElemSpaces), [&](TupleTypeElt ty){ - return Space(ty.getType()); + return Space(ty.getType(), ty.getName()); }); } else if (auto *TTy = dyn_cast(eedTy.getPointer())) { - constElemSpaces.push_back(Space(TTy->getUnderlyingType())); + constElemSpaces.push_back(Space(TTy->getUnderlyingType(), + Identifier())); } } return Space(tp, eed->getName(), @@ -882,7 +896,7 @@ namespace { std::transform(TTy->getElements().begin(), TTy->getElements().end(), std::back_inserter(constElemSpaces), [&](TupleTypeElt ty){ - return Space(ty.getType()); + return Space(ty.getType(), ty.getName()); }); // Create an empty constructor head for the tuple space. arr.push_back(Space(tp, Identifier(), /*canDowngrade*/false, @@ -917,8 +931,7 @@ namespace { bool sawDowngradablePattern = false; bool sawRedundantPattern = false; SmallVector spaces; - for (unsigned i = 0, e = Switch->getCases().size(); i < e; ++i) { - auto *caseBlock = Switch->getCases()[i]; + for (auto *caseBlock : Switch->getCases()) { for (auto &caseItem : caseBlock->getCaseLabelItems()) { // 'where'-clauses on cases mean the case does not contribute to // the exhaustiveness of the pattern. @@ -943,7 +956,7 @@ namespace { } } - Space totalSpace(Switch->getSubjectExpr()->getType()); + Space totalSpace(Switch->getSubjectExpr()->getType(), Identifier()); Space coveredSpace(spaces); size_t totalSpaceSize = totalSpace.getSize(TC); if (totalSpaceSize > Space::getMaximumSize()) { @@ -1090,7 +1103,7 @@ namespace { } } - TC.diagnose(startLoc, diag::non_exhaustive_switch); + TC.diagnose(startLoc, mainDiagType); TC.diagnose(startLoc, diag::missing_several_cases, false) .fixItInsert(endLoc, buffer.str()); } else { @@ -1218,8 +1231,9 @@ namespace { bool &sawDowngradablePattern) { switch (item->getKind()) { case PatternKind::Any: + return Space(item->getType(), Identifier()); case PatternKind::Named: - return Space(item->getType()); + return Space(item->getType(), cast(item)->getBoundName()); case PatternKind::Bool: { return Space(cast(item)->getValue()); } @@ -1231,7 +1245,7 @@ namespace { // These coercions are irrefutable. Project with the original type // instead of the cast's target type to maintain consistency with the // scrutinee's type. - return Space(IP->getType()); + return Space(IP->getType(), Identifier()); case CheckedCastKind::Unresolved: case CheckedCastKind::ValueCast: case CheckedCastKind::ArrayDowncast: @@ -1316,7 +1330,7 @@ namespace { || SP->getKind() == PatternKind::Tuple) { if (auto *TTy = SP->getType()->getAs()) { for (auto ty : TTy->getElements()) { - conArgSpace.push_back(Space(ty.getType())); + conArgSpace.push_back(Space(ty.getType(), ty.getName())); } } else { conArgSpace.push_back(projectPattern(TC, SP, diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 1af95ec27d3..390fa00197f 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -252,12 +252,13 @@ findDeclContextForType(TypeChecker &TC, // protocol extension, always use the nominal type and // not the protocol 'Self' type. if (isa(typeDecl)) - return resolver->resolveTypeOfDecl( - DC->getAsNominalTypeOrNominalTypeExtensionContext()); + return resolver->mapTypeIntoContext( + DC->getDeclaredInterfaceType()); // Otherwise, we want the protocol 'Self' type for // substituting into alias types and associated types. - return resolver->resolveTypeOfContext(DC); + return resolver->mapTypeIntoContext( + DC->getSelfInterfaceType()); }; // First, check for direct containment in one of our parent contexts. @@ -357,7 +358,8 @@ findDeclContextForType(TypeChecker &TC, } } else { // Get the substituted superclass type, if any. - superclass = resolver->resolveTypeOfContext(parentDC)->getSuperclass(); + superclass = resolver->mapTypeIntoContext( + parentDC->getSelfInterfaceType())->getSuperclass(); // Start with the type of the current context. auto fromNominal = parentDC->getAsNominalTypeOrNominalTypeExtensionContext(); @@ -435,12 +437,14 @@ Type TypeChecker::resolveTypeInContext( auto *parentNominal = parentDC->getAsNominalTypeOrNominalTypeExtensionContext(); if (parentNominal == nominalType) - return resolver->resolveTypeOfContext(parentDC); + return resolver->mapTypeIntoContext( + parentDC->getSelfInterfaceType()); if (isa(parentDC)) { auto *extendedType = parentNominal; while (extendedType != nullptr) { if (extendedType == nominalType) - return resolver->resolveTypeOfDecl(extendedType); + return resolver->mapTypeIntoContext( + extendedType->getDeclaredInterfaceType()); extendedType = extendedType->getParent() ->getAsNominalTypeOrNominalTypeExtensionContext(); } @@ -451,9 +455,9 @@ Type TypeChecker::resolveTypeInContext( // If we found a generic parameter, map to the archetype if there is one. if (auto genericParam = dyn_cast(typeDecl)) { - return resolver->resolveGenericTypeParamType( - genericParam->getDeclaredInterfaceType() - ->castTo()); + assert(!selfType); + return resolver->mapTypeIntoContext( + genericParam->getDeclaredInterfaceType()); } // Simple case -- the type is not nested inside of another type. @@ -467,7 +471,8 @@ Type TypeChecker::resolveTypeInContext( return aliasDecl->getUnboundGenericType(); // Otherwise, simply return the underlying type. - return resolver->resolveTypeOfDecl(aliasDecl); + return resolver->mapTypeIntoContext( + aliasDecl->getDeclaredInterfaceType()); } // When a nominal type used outside its context, return the unbound @@ -479,14 +484,6 @@ Type TypeChecker::resolveTypeInContext( return typeDecl->getDeclaredInterfaceType(); } - // If we started from a protocol and found an associated type member - // of a (possibly inherited) protocol, resolve it via the resolver. - if (auto *assocType = dyn_cast(typeDecl)) { - if (selfType->isTypeParameter()) - return resolver->resolveSelfAssociatedType( - selfType, assocType); - } - // Finally, substitute the base type into the member type. return substMemberTypeWithBase(fromDC->getParentModule(), typeDecl, selfType); @@ -868,7 +865,8 @@ static Type diagnoseUnknownType(TypeChecker &tc, DeclContext *dc, // Retrieve the nominal type and resolve it within this context. assert(!isa(nominal) && "Cannot be a protocol"); - auto type = resolver->resolveTypeOfContext(dc->getInnermostTypeContext()); + auto type = resolver->mapTypeIntoContext( + dc->getInnermostTypeContext()->getSelfInterfaceType()); if (type->hasError()) return type; @@ -1163,7 +1161,8 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, DeclContext *DC, // The issue is though that ComponentIdentTypeRepr only accepts a ValueDecl // while the 'Self' type is more than just a reference to a TypeDecl. - auto selfType = resolver->resolveTypeOfContext(func->getDeclContext()); + auto selfType = resolver->mapTypeIntoContext( + func->getDeclContext()->getSelfInterfaceType()); return DynamicSelfType::get(selfType, TC.Context); } @@ -2334,7 +2333,7 @@ Type TypeResolver::resolveASTFunctionType(FunctionTypeRepr *repr, if (const auto Tuple = dyn_cast(args)) { if (Tuple->getNumElements() == 1) { if (const auto Void = - dyn_cast(Tuple->getElement(0))) { + dyn_cast(Tuple->getElementType(0))) { if (Void->getIdentifier().str() == "Void") { TC.diagnose(args->getStartLoc(), diag::paren_void_probably_void) .fixItReplace(args->getSourceRange(), "()"); @@ -2491,13 +2490,13 @@ Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr, TC.diagnose(tuple->getEllipsisLoc(), diag::sil_function_ellipsis); } // SIL functions cannot have parameter names. - for (auto nameLoc : tuple->getUnderscoreLocs()) { - if (nameLoc.isValid()) - TC.diagnose(nameLoc, diag::sil_function_input_label); + for (auto &element : tuple->getElements()) { + if (element.UnderscoreLoc.isValid()) + TC.diagnose(element.UnderscoreLoc, diag::sil_function_input_label); } for (auto elt : tuple->getElements()) { - auto param = resolveSILParameter(elt, + auto param = resolveSILParameter(elt.Type, options | TR_ImmediateFunctionInput); params.push_back(param); if (!param.getType()) return nullptr; @@ -2699,12 +2698,12 @@ bool TypeResolver::resolveSILResults(TypeRepr *repr, Optional &errorResult) { if (auto tuple = dyn_cast(repr)) { bool hadError = false; - for (auto nameLoc : tuple->getUnderscoreLocs()) { - if (nameLoc.isValid()) - TC.diagnose(nameLoc, diag::sil_function_output_label); + for (auto &element : tuple->getElements()) { + if (element.UnderscoreLoc.isValid()) + TC.diagnose(element.UnderscoreLoc, diag::sil_function_output_label); } for (auto elt : tuple->getElements()) { - if (resolveSingleSILResult(elt, options, ordinaryResults, errorResult)) + if (resolveSingleSILResult(elt.Type, options, ordinaryResults, errorResult)) hadError = true; } return hadError; @@ -2867,7 +2866,7 @@ Type TypeResolver::resolveTupleType(TupleTypeRepr *repr, } for (unsigned i = 0, end = repr->getNumElements(); i != end; ++i) { - auto *tyR = repr->getElement(i); + auto *tyR = repr->getElementType(i); Type ty; Identifier name; bool variadic = false; @@ -2913,7 +2912,7 @@ Type TypeResolver::resolveTupleType(TupleTypeRepr *repr, TC.diagnose(repr->getElementNameLoc(0), diag::tuple_single_element) .fixItRemoveChars(repr->getElementNameLoc(0), - repr->getElement(0)->getStartLoc()); + repr->getElementType(0)->getStartLoc()); } elements[0] = TupleTypeElt(elements[0].getType()); diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp index 8e8ecd273b2..024ad6a3bc9 100644 --- a/lib/Sema/TypeChecker.cpp +++ b/lib/Sema/TypeChecker.cpp @@ -622,7 +622,8 @@ void swift::performTypeChecking(SourceFile &SF, TopLevelContext &TLC, OptionSet Options, unsigned StartElem, unsigned WarnLongFunctionBodies, - unsigned WarnLongExpressionTypeChecking) { + unsigned WarnLongExpressionTypeChecking, + unsigned ExpressionTimeoutThreshold) { if (SF.ASTStage == SourceFile::TypeChecked) return; @@ -648,6 +649,9 @@ void swift::performTypeChecking(SourceFile &SF, TopLevelContext &TLC, if (MyTC) { MyTC->setWarnLongFunctionBodies(WarnLongFunctionBodies); MyTC->setWarnLongExpressionTypeChecking(WarnLongExpressionTypeChecking); + if (ExpressionTimeoutThreshold != 0) + MyTC->setExpressionTimeoutThreshold(ExpressionTimeoutThreshold); + if (Options.contains(TypeCheckingFlags::DebugTimeFunctionBodies)) MyTC->enableDebugTimeFunctionBodies(); @@ -979,7 +983,8 @@ void TypeChecker::checkForForbiddenPrefix(const Decl *D) { if (!hasEnabledForbiddenTypecheckPrefix()) return; if (auto VD = dyn_cast(D)) { - checkForForbiddenPrefix(VD->getNameStr()); + if (!VD->getBaseName().isSpecial()) + checkForForbiddenPrefix(VD->getBaseName().getIdentifier().str()); } } diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index d8072714a29..bddca169cfa 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -829,12 +829,16 @@ private: /// Intended for debugging purposes only. unsigned WarnLongFunctionBodies = 0; - /// If \p timeInMS is non-zero, warn when type-chcking an expression - /// takes longer than this many milliseconds. + /// If non-zero, warn when type-chcking an expression takes longer + /// than this many milliseconds. /// /// Intended for debugging purposes only. unsigned WarnLongExpressionTypeChecking = 0; + /// If non-zero, abort the expression type checker if it takes more + /// than this many seconds. + unsigned ExpressionTimeoutThreshold = 600; + /// If true, the time it takes to type-check each function will be dumped /// to llvm::errs(). bool DebugTimeFunctionBodies = false; @@ -870,6 +874,10 @@ public: DebugTimeExpressions = true; } + bool getDebugTimeExpressions() { + return DebugTimeExpressions; + } + /// If \p timeInMS is non-zero, warn when a function body takes longer than /// this many milliseconds to type-check. /// @@ -878,7 +886,7 @@ public: WarnLongFunctionBodies = timeInMS; } - /// If \p timeInMS is non-zero, warn when type-chcking an expression + /// If \p timeInMS is non-zero, warn when type-checking an expression /// takes longer than this many milliseconds. /// /// Intended for debugging purposes only. @@ -886,6 +894,28 @@ public: WarnLongExpressionTypeChecking = timeInMS; } + /// Return the current setting for the number of milliseconds + /// threshold we use to determine whether to warn about an + /// expression taking a long time. + unsigned getWarnLongExpressionTypeChecking() { + return WarnLongExpressionTypeChecking; + } + + /// Set the threshold that determines the upper bound for the number + /// of seconds we'll let the expression type checker run before + /// considering an expression "too complex". + void setExpressionTimeoutThreshold(unsigned timeInSeconds) { + ExpressionTimeoutThreshold = timeInSeconds; + } + + /// Return the current settting for the threshold that determines + /// the upper bound for the number of seconds we'll let the + /// expression type checker run before considering an expression + /// "too complex". + unsigned getExpressionTimeoutThresholdInSeconds() { + return ExpressionTimeoutThreshold; + } + bool getInImmediateMode() { return InImmediateMode; } @@ -1547,6 +1577,12 @@ public: FreeTypeVariableBinding::Disallow, ExprTypeCheckListener *listener = nullptr); + void getPossibleTypesOfExpressionWithoutApplying( + Expr *&expr, DeclContext *dc, SmallVectorImpl &types, + FreeTypeVariableBinding allowFreeTypeVariables = + FreeTypeVariableBinding::Disallow, + ExprTypeCheckListener *listener = nullptr); + bool typeCheckCompletionSequence(Expr *&expr, DeclContext *DC); /// \brief Type check the given expression assuming that its children @@ -1854,6 +1890,11 @@ public: ConformanceCheckOptions options, SourceLoc ComplainLoc, UnsatisfiedDependency *unsatisfiedDependency); + /// Mark the given protocol conformance as "used" from the given declaration + /// context. + void markConformanceUsed(ProtocolConformanceRef conformance, + DeclContext *dc); + /// Functor class suitable for use as a \c LookupConformanceFn to look up a /// conformance through a particular declaration context using the given /// type checker. diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 6b81a3cd738..5b53160efa9 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -3805,17 +3805,17 @@ Expected ModuleFile::getTypeChecked(TypeID TID) { case decls_block::PAREN_TYPE: { TypeID underlyingID; - bool isVariadic, isAutoClosure, isEscaping; + bool isVariadic, isAutoClosure, isEscaping, isInOut; decls_block::ParenTypeLayout::readRecord(scratch, underlyingID, isVariadic, - isAutoClosure, isEscaping); + isAutoClosure, isEscaping, isInOut); auto underlyingTy = getTypeChecked(underlyingID); if (!underlyingTy) return underlyingTy.takeError(); - + typeOrOffset = ParenType::get( ctx, underlyingTy.get(), - ParameterTypeFlags(isVariadic, isAutoClosure, isEscaping)); + ParameterTypeFlags(isVariadic, isAutoClosure, isEscaping, isInOut)); break; } @@ -3835,17 +3835,17 @@ Expected ModuleFile::getTypeChecked(TypeID TID) { IdentifierID nameID; TypeID typeID; - bool isVariadic, isAutoClosure, isEscaping; + bool isVariadic, isAutoClosure, isEscaping, isInOut; decls_block::TupleTypeEltLayout::readRecord( - scratch, nameID, typeID, isVariadic, isAutoClosure, isEscaping); + scratch, nameID, typeID, isVariadic, isAutoClosure, isEscaping, isInOut); auto elementTy = getTypeChecked(typeID); if (!elementTy) return elementTy.takeError(); - + elements.emplace_back( elementTy.get(), getIdentifier(nameID), - ParameterTypeFlags(isVariadic, isAutoClosure, isEscaping)); + ParameterTypeFlags(isVariadic, isAutoClosure, isEscaping, isInOut)); } typeOrOffset = TupleType::get(elements, ctx); diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index 50e7df9bd9d..7e8da77907b 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -2143,6 +2143,18 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, {}, type)); break; } + case KeyPathComponentKindEncoding::OptionalChain: + components.push_back(KeyPathPatternComponent::forOptional( + KeyPathPatternComponent::Kind::OptionalChain, type)); + break; + case KeyPathComponentKindEncoding::OptionalForce: + components.push_back(KeyPathPatternComponent::forOptional( + KeyPathPatternComponent::Kind::OptionalForce, type)); + break; + case KeyPathComponentKindEncoding::OptionalWrap: + components.push_back(KeyPathPatternComponent::forOptional( + KeyPathPatternComponent::Kind::OptionalWrap, type)); + break; } } diff --git a/lib/Serialization/SILFormat.h b/lib/Serialization/SILFormat.h index c7efa322c9c..959622f542c 100644 --- a/lib/Serialization/SILFormat.h +++ b/lib/Serialization/SILFormat.h @@ -73,6 +73,9 @@ enum class KeyPathComponentKindEncoding : uint8_t { StoredProperty, GettableProperty, SettableProperty, + OptionalChain, + OptionalForce, + OptionalWrap, }; enum class KeyPathComputedComponentIdKindEncoding : uint8_t { Property, diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index d144ea973e1..c78de3f6848 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3248,7 +3248,7 @@ void Serializer::writeType(Type ty) { ParenTypeLayout::emitRecord( Out, ScratchRecord, abbrCode, addTypeRef(parenTy->getUnderlyingType()), paramFlags.isVariadic(), paramFlags.isAutoClosure(), - paramFlags.isEscaping()); + paramFlags.isEscaping(), paramFlags.isInOut()); break; } @@ -3264,7 +3264,8 @@ void Serializer::writeType(Type ty) { TupleTypeEltLayout::emitRecord( Out, ScratchRecord, abbrCode, addDeclBaseNameRef(elt.getName()), addTypeRef(elt.getType()), paramFlags.isVariadic(), - paramFlags.isAutoClosure(), paramFlags.isEscaping()); + paramFlags.isAutoClosure(), paramFlags.isEscaping(), + paramFlags.isInOut()); } break; diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index b3cc98f9956..1a5bcca9853 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -1900,6 +1900,15 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { assert(component.getComputedPropertyIndices().empty() && "indices not implemented"); break; + case KeyPathPatternComponent::Kind::OptionalChain: + handleComponentCommon(KeyPathComponentKindEncoding::OptionalChain); + break; + case KeyPathPatternComponent::Kind::OptionalForce: + handleComponentCommon(KeyPathComponentKindEncoding::OptionalForce); + break; + case KeyPathPatternComponent::Kind::OptionalWrap: + handleComponentCommon(KeyPathComponentKindEncoding::OptionalWrap); + break; } } diff --git a/lib/Syntax/CMakeLists.txt b/lib/Syntax/CMakeLists.txt index 1d20b1b8a6d..fe642f2fcc6 100644 --- a/lib/Syntax/CMakeLists.txt +++ b/lib/Syntax/CMakeLists.txt @@ -2,7 +2,7 @@ add_swift_library(swiftSyntax STATIC DeclSyntax.cpp ExprSyntax.cpp Format.cpp - TokenSyntax.cpp + RawTokenSyntax.cpp GenericSyntax.cpp LegacyASTTransformer.cpp Trivia.cpp diff --git a/lib/Syntax/DeclSyntax.cpp b/lib/Syntax/DeclSyntax.cpp index 7160508fb2b..a29550517da 100644 --- a/lib/Syntax/DeclSyntax.cpp +++ b/lib/Syntax/DeclSyntax.cpp @@ -21,173 +21,80 @@ using namespace swift; using namespace swift::syntax; -#pragma mark - declaration Data - -DeclSyntaxData::DeclSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : SyntaxData(Raw, Parent, IndexInParent) { - assert(Raw->isDecl()); -} - #pragma mark - declaration API -DeclSyntax::DeclSyntax(const RC Root, const DeclSyntaxData *Data) - : Syntax(Root, Data) {} - -#pragma mark - declaration-modifier Data - -DeclModifierSyntaxData:: -DeclModifierSyntaxData(const RC Raw, - const SyntaxData *Parent, - const CursorIndex IndexInParent) - : SyntaxData(Raw, Parent, IndexInParent) { - assert(Raw->Kind == SyntaxKind::DeclModifier); - assert(Raw->Layout.size() == 4); -#ifndef NDEBUG - auto Name = - cast(Raw->getChild(DeclModifierSyntax::Cursor::Name)); - auto Kind = Name->getTokenKind(); - assert(Kind == tok::kw_class || - Kind == tok::kw_static || - Kind == tok::identifier || - Kind == tok::kw_public || - Kind == tok::kw_private || - Kind == tok::kw_fileprivate || - Kind == tok::kw_internal); -#endif - syntax_assert_child_token_text(Raw, DeclModifierSyntax::Cursor::LeftParen, - tok::l_paren, "("); - syntax_assert_child_token(Raw, DeclModifierSyntax::Cursor::Argument, - tok::identifier); - syntax_assert_child_token_text(Raw, DeclModifierSyntax::Cursor::RightParen, - tok::r_paren, ")"); +void DeclModifierSyntax::validate() const { + assert(Data->Raw->isDecl()); } -RC -DeclModifierSyntaxData::make(const RC Raw, - const SyntaxData *Parent, - const CursorIndex IndexInParent) { - return RC{ - new DeclModifierSyntaxData { - Raw, Parent, IndexInParent - } - }; -} - -RC DeclModifierSyntaxData::makeBlank() { - auto Raw = RawSyntax::make(SyntaxKind::DeclModifier, - { - TokenSyntax::missingToken(tok::identifier, ""), - TokenSyntax::missingToken(tok::l_paren, "("), - TokenSyntax::missingToken(tok::identifier, ""), - TokenSyntax::missingToken(tok::r_paren, ")"), - }, - SourcePresence::Present); - return make(Raw); +DeclModifierSyntax DeclModifierSyntax::makeBlank() { + return make( + RawSyntax::make(SyntaxKind::DeclModifier, + { + RawTokenSyntax::missingToken(tok::identifier, ""), + RawTokenSyntax::missingToken(tok::l_paren, "("), + RawTokenSyntax::missingToken(tok::identifier, ""), + RawTokenSyntax::missingToken(tok::r_paren, ")"), + }, + SourcePresence::Present)); } #pragma mark - declaration-modifier API -RC DeclModifierSyntax::getName() const { - return cast(getRaw()->getChild(Cursor::Name)); +TokenSyntax DeclModifierSyntax::getName() const { + return { Root, Data->getChild(Cursor::Name).get() }; } -DeclModifierSyntax DeclModifierSyntax::withName(RC NewName) const { - assert(NewName->getTokenKind() == tok::identifier); - return Data->replaceChild(NewName, Cursor::Name); +DeclModifierSyntax DeclModifierSyntax::withName(TokenSyntax NewName) const { + assert(NewName.getTokenKind() == tok::identifier); + return Data->replaceChild(NewName.getRaw(), Cursor::Name); } -RC DeclModifierSyntax::getLeftParenToken() const { - return cast(getRaw()->getChild(Cursor::LeftParen)); +TokenSyntax DeclModifierSyntax::getLeftParenToken() const { + return { Root, Data->getChild(Cursor::LeftParen).get() }; } DeclModifierSyntax -DeclModifierSyntax::withLeftParenToken(RC NewLeftParen) const { +DeclModifierSyntax::withLeftParenToken(TokenSyntax NewLeftParen) const { syntax_assert_token_is(NewLeftParen, tok::l_paren, "("); - return Data->replaceChild(NewLeftParen, + return Data->replaceChild(NewLeftParen.getRaw(), Cursor::LeftParen); } -RC DeclModifierSyntax::getArgument() const { - return cast(getRaw()->getChild(Cursor::Argument)); +TokenSyntax DeclModifierSyntax::getArgument() const { + return { Root, Data->getChild(Cursor::Argument).get() }; } DeclModifierSyntax -DeclModifierSyntax::withArgument(RC NewArgument) const { - assert(NewArgument->getTokenKind() == tok::identifier); - return Data->replaceChild(NewArgument, Cursor::Argument); +DeclModifierSyntax::withArgument(TokenSyntax NewArgument) const { + assert(NewArgument.getTokenKind() == tok::identifier); + return Data->replaceChild(NewArgument.getRaw(), + Cursor::Argument); } -RC DeclModifierSyntax::getRightParenToken() const { - return cast(getRaw()->getChild(Cursor::RightParen)); +TokenSyntax DeclModifierSyntax::getRightParenToken() const { + return { Root, Data->getChild(Cursor::RightParen).get() }; } DeclModifierSyntax -DeclModifierSyntax::withRightParenToken(RC NewRightParen) const { +DeclModifierSyntax::withRightParenToken(TokenSyntax NewRightParen) const { syntax_assert_token_is(NewRightParen, tok::r_paren, ")"); - return Data->replaceChild(NewRightParen, + return Data->replaceChild(NewRightParen.getRaw(), Cursor::RightParen); } -#pragma mark - unknown-statement Data - -UnknownDeclSyntaxData::UnknownDeclSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : UnknownSyntaxData(Raw, Parent, IndexInParent) { - assert(Raw->Kind == SyntaxKind::UnknownDecl); -} - -RC -UnknownDeclSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - auto UnknownRaw = RawSyntax::make(SyntaxKind::UnknownDecl, Raw->Layout, - Raw->Presence); - return RC { - new UnknownDeclSyntaxData { - Raw, Parent, IndexInParent - } - }; -} - #pragma mark - unknown-statement API -UnknownDeclSyntax::UnknownDeclSyntax(const RC Root, - const UnknownDeclSyntaxData *Data) - : UnknownSyntax(Root, Data) {} - -#pragma mark - declaration-members Data - -DeclMembersSyntaxData::DeclMembersSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : SyntaxData(Raw, Parent, IndexInParent) { - assert(Raw->Kind == SyntaxKind::DeclMembers); -} - -RC -DeclMembersSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new DeclMembersSyntaxData { - Raw, Parent, IndexInParent - } - }; -} - -RC DeclMembersSyntaxData::makeBlank() { - return make(RawSyntax::make(SyntaxKind::DeclMembers, {}, - SourcePresence::Present)); +void UnknownDeclSyntax::validate() const { + assert(Data->Raw->Kind == SyntaxKind::UnknownDecl); } #pragma mark - declaration-members API -DeclMembersSyntax::DeclMembersSyntax(const RC Root, - const DeclMembersSyntaxData *Data) - : Syntax(Root, Data) {} +DeclMembersSyntax DeclMembersSyntax::makeBlank() { + return make(RawSyntax::make(SyntaxKind::DeclMembers, {}, + SourcePresence::Present)); +} #pragma mark - declaration-members Builder @@ -200,83 +107,71 @@ DeclMembersSyntaxBuilder::addMember(DeclSyntax Member) { DeclMembersSyntax DeclMembersSyntaxBuilder::build() const { auto Raw = RawSyntax::make(SyntaxKind::DeclMembers, MembersLayout, SourcePresence::Present); - auto Data = DeclMembersSyntaxData::make(Raw); + auto Data = SyntaxData::make(Raw); return DeclMembersSyntax { Data, Data.get() }; } #pragma mark - struct-declaration Data -StructDeclSyntaxData::StructDeclSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : DeclSyntaxData(Raw, Parent, IndexInParent) { - assert(Raw->Kind == SyntaxKind::StructDecl); - syntax_assert_child_token_text(Raw, StructDeclSyntax::Cursor::StructKeyword, +void StructDeclSyntax::validate() const { + assert(Data->Raw->Kind == SyntaxKind::StructDecl); + syntax_assert_child_token_text(Data->Raw, + StructDeclSyntax::Cursor::StructKeyword, tok::kw_struct, "struct"); - syntax_assert_child_token(Raw, StructDeclSyntax::Cursor::Identifier, + syntax_assert_child_token(Data->Raw, StructDeclSyntax::Cursor::Identifier, tok::identifier); - syntax_assert_child_kind(Raw, + syntax_assert_child_kind(Data->Raw, StructDeclSyntax::Cursor::GenericParameterClause, SyntaxKind::GenericParameterClause); - syntax_assert_child_kind(Raw, StructDeclSyntax::Cursor::GenericWhereClause, + syntax_assert_child_kind(Data->Raw, + StructDeclSyntax::Cursor::GenericWhereClause, SyntaxKind::GenericWhereClause); - syntax_assert_child_token_text(Raw, StructDeclSyntax::Cursor::LeftBrace, + syntax_assert_child_token_text(Data->Raw, StructDeclSyntax::Cursor::LeftBrace, tok::l_brace, "{"); - syntax_assert_child_kind(Raw, StructDeclSyntax::Cursor::Members, + syntax_assert_child_kind(Data->Raw, StructDeclSyntax::Cursor::Members, SyntaxKind::DeclMembers); - syntax_assert_child_token_text(Raw, StructDeclSyntax::Cursor::RightBrace, + syntax_assert_child_token_text(Data->Raw, + StructDeclSyntax::Cursor::RightBrace, tok::r_brace, "}"); } -RC StructDeclSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new StructDeclSyntaxData { Raw, Parent, IndexInParent } - }; -} - -RC StructDeclSyntaxData::makeBlank() { - return make(RawSyntax::make(SyntaxKind::StructDecl, +StructDeclSyntax StructDeclSyntax::makeBlank() { + return make(RawSyntax::make(SyntaxKind::StructDecl, { - TokenSyntax::missingToken(tok::kw_struct, "struct"), - TokenSyntax::missingToken(tok::identifier, ""), + RawTokenSyntax::missingToken(tok::kw_struct, "struct"), + RawTokenSyntax::missingToken(tok::identifier, ""), RawSyntax::missing(SyntaxKind::GenericParameterClause), RawSyntax::missing(SyntaxKind::GenericWhereClause), - TokenSyntax::missingToken(tok::l_brace, "{"), + RawTokenSyntax::missingToken(tok::l_brace, "{"), RawSyntax::missing(SyntaxKind::DeclMembers), - TokenSyntax::missingToken(tok::r_brace, "}"), + RawTokenSyntax::missingToken(tok::r_brace, "}"), }, SourcePresence::Present)); } #pragma mark - struct-declaration API -StructDeclSyntax::StructDeclSyntax(const RC Root, - const StructDeclSyntaxData *Data) - : DeclSyntax(Root, Data) {} - -RC StructDeclSyntax::getStructKeyword() const { - return cast(getRaw()->getChild(Cursor::StructKeyword)); +TokenSyntax StructDeclSyntax::getStructKeyword() const { + return { Root, Data->getChild(Cursor::StructKeyword).get() }; } StructDeclSyntax -StructDeclSyntax::withStructKeyword(RC NewStructKeyword) +StructDeclSyntax::withStructKeyword(TokenSyntax NewStructKeyword) const { syntax_assert_token_is(NewStructKeyword, tok::kw_struct, "struct"); - return Data->replaceChild(NewStructKeyword, + return Data->replaceChild(NewStructKeyword.getRaw(), Cursor::StructKeyword); } StructDeclSyntax -StructDeclSyntax::withLeftBrace(RC NewLeftBrace) const { +StructDeclSyntax::withLeftBrace(TokenSyntax NewLeftBrace) const { syntax_assert_token_is(NewLeftBrace, tok::l_brace, "{"); - return Data->replaceChild(NewLeftBrace, + return Data->replaceChild(NewLeftBrace.getRaw(), Cursor::LeftBrace); } -RC StructDeclSyntax::getLeftBraceToken() const { - return cast(getRaw()->getChild(Cursor::LeftBrace)); +TokenSyntax StructDeclSyntax::getLeftBraceToken() const { + return { Root, Data->getChild(Cursor::LeftBrace).get() }; } StructDeclSyntax @@ -286,12 +181,7 @@ StructDeclSyntax::withMembers(DeclMembersSyntax NewMembers) const { } DeclMembersSyntax StructDeclSyntax::getMembers() const { - auto Raw = getRaw()->getChild(Cursor::Members); - auto MembersData = DeclMembersSyntaxData::make(Raw, - Data, - cursorIndex(Cursor::Members)); - const_cast(getData())->CachedMembers = MembersData; - return DeclMembersSyntax { Root, MembersData.get() }; + return DeclMembersSyntax { Root, Data->getChild(Cursor::Members).get() }; } #pragma mark - struct-declaration Builder @@ -300,26 +190,26 @@ StructDeclSyntaxBuilder::StructDeclSyntaxBuilder() : StructLayout(SyntaxFactory::makeBlankStructDecl().getRaw()->Layout) {} StructDeclSyntaxBuilder & -StructDeclSyntaxBuilder::useStructKeyword(RC StructKeyword) { +StructDeclSyntaxBuilder::useStructKeyword(TokenSyntax StructKeyword) { syntax_assert_token_is(StructKeyword, tok::kw_struct, "struct"); auto Index = cursorIndex(StructDeclSyntax::Cursor::StructKeyword); - StructLayout[Index] = StructKeyword; + StructLayout[Index] = StructKeyword.getRaw(); return *this; } StructDeclSyntaxBuilder & -StructDeclSyntaxBuilder::useIdentifier(RC Identifier) { - assert(Identifier->getTokenKind() == tok::identifier); +StructDeclSyntaxBuilder::useIdentifier(TokenSyntax Identifier) { + assert(Identifier.getTokenKind() == tok::identifier); auto Index = cursorIndex(StructDeclSyntax::Cursor::Identifier); - StructLayout[Index] = Identifier; + StructLayout[Index] = Identifier.getRaw(); return *this; } StructDeclSyntaxBuilder & -StructDeclSyntaxBuilder::useLeftBrace(RC LeftBrace) { +StructDeclSyntaxBuilder::useLeftBrace(TokenSyntax LeftBrace) { syntax_assert_token_is(LeftBrace, tok::l_brace, "{"); auto Index = cursorIndex(StructDeclSyntax::Cursor::LeftBrace); - StructLayout[Index] = LeftBrace; + StructLayout[Index] = LeftBrace.getRaw(); return *this; } @@ -331,44 +221,28 @@ StructDeclSyntaxBuilder::useMembers(DeclMembersSyntax Members) { } StructDeclSyntaxBuilder & -StructDeclSyntaxBuilder::useRightBrace(RC RightBrace) { +StructDeclSyntaxBuilder::useRightBrace(TokenSyntax RightBrace) { syntax_assert_token_is(RightBrace, tok::r_brace, "}"); auto Index = cursorIndex(StructDeclSyntax::Cursor::RightBrace); - StructLayout[Index] = RightBrace; + StructLayout[Index] = RightBrace.getRaw(); return *this; } StructDeclSyntax StructDeclSyntaxBuilder::build() const { auto Raw = RawSyntax::make(SyntaxKind::StructDecl, StructLayout, SourcePresence::Present); - auto Data = StructDeclSyntaxData::make(Raw); + auto Data = SyntaxData::make(Raw); return StructDeclSyntax { Data, Data.get() }; } -#pragma mark - type-alias Data - -TypeAliasDeclSyntaxData::TypeAliasDeclSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : DeclSyntaxData(Raw, Parent, IndexInParent) {} - -RC -TypeAliasDeclSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new TypeAliasDeclSyntaxData { Raw, Parent, IndexInParent } - }; -} - -RC -TypeAliasDeclSyntaxData::makeBlank() { - return make(RawSyntax::make(SyntaxKind::TypeAliasDecl, +TypeAliasDeclSyntax +TypeAliasDeclSyntax::makeBlank() { + return make(RawSyntax::make(SyntaxKind::TypeAliasDecl, { - TokenSyntax::missingToken(tok::kw_typealias, "typealias"), - TokenSyntax::missingToken(tok::identifier, ""), + RawTokenSyntax::missingToken(tok::kw_typealias, "typealias"), + RawTokenSyntax::missingToken(tok::identifier, ""), RawSyntax::missing(SyntaxKind::GenericParameterClause), - TokenSyntax::missingToken(tok::equal, "="), + RawTokenSyntax::missingToken(tok::equal, "="), RawSyntax::missing(SyntaxKind::MissingType), }, SourcePresence::Present)); @@ -376,21 +250,17 @@ TypeAliasDeclSyntaxData::makeBlank() { #pragma mark - type-alias API -TypeAliasDeclSyntax::TypeAliasDeclSyntax(RC Root, - const TypeAliasDeclSyntaxData *Data) - : DeclSyntax(Root, Data) {} - TypeAliasDeclSyntax TypeAliasDeclSyntax:: -withTypeAliasKeyword(RC NewTypeAliasKeyword) const { +withTypeAliasKeyword(TokenSyntax NewTypeAliasKeyword) const { syntax_assert_token_is(NewTypeAliasKeyword, tok::kw_typealias, "typealias"); - return Data->replaceChild(NewTypeAliasKeyword, + return Data->replaceChild(NewTypeAliasKeyword.getRaw(), Cursor::TypeAliasKeyword); } TypeAliasDeclSyntax -TypeAliasDeclSyntax::withIdentifier(RC NewIdentifier) const { - assert(NewIdentifier->getTokenKind() == tok::identifier); - return Data->replaceChild(NewIdentifier, +TypeAliasDeclSyntax::withIdentifier(TokenSyntax NewIdentifier) const { + assert(NewIdentifier.getTokenKind() == tok::identifier); + return Data->replaceChild(NewIdentifier.getRaw(), Cursor::Identifier); } @@ -402,9 +272,9 @@ const { } TypeAliasDeclSyntax -TypeAliasDeclSyntax::withEqualToken(RC NewEqualToken) const { +TypeAliasDeclSyntax::withEqualToken(TokenSyntax NewEqualToken) const { syntax_assert_token_is(NewEqualToken, tok::equal, "="); - return Data->replaceChild(NewEqualToken, + return Data->replaceChild(NewEqualToken.getRaw(), Cursor::EqualToken); } @@ -421,18 +291,18 @@ TypeAliasDeclSyntaxBuilder::TypeAliasDeclSyntaxBuilder() {} TypeAliasDeclSyntaxBuilder &TypeAliasDeclSyntaxBuilder:: -useTypeAliasKeyword(RC TypeAliasKeyword) { +useTypeAliasKeyword(TokenSyntax TypeAliasKeyword) { syntax_assert_token_is(TypeAliasKeyword, tok::kw_typealias, "typealias"); auto Index = cursorIndex(TypeAliasDeclSyntax::Cursor::TypeAliasKeyword); - TypeAliasLayout[Index] = TypeAliasKeyword; + TypeAliasLayout[Index] = TypeAliasKeyword.getRaw(); return *this; } TypeAliasDeclSyntaxBuilder & -TypeAliasDeclSyntaxBuilder::useIdentifier(RC Identifier) { - assert(Identifier->getTokenKind() == tok::identifier); +TypeAliasDeclSyntaxBuilder::useIdentifier(TokenSyntax Identifier) { + assert(Identifier.getTokenKind() == tok::identifier); auto Index = cursorIndex(TypeAliasDeclSyntax::Cursor::Identifier); - TypeAliasLayout[Index] = Identifier; + TypeAliasLayout[Index] = Identifier.getRaw(); return *this; } @@ -444,9 +314,9 @@ useGenericParameterClause(GenericParameterClauseSyntax GenericParams) { } TypeAliasDeclSyntaxBuilder & -TypeAliasDeclSyntaxBuilder::useEqualToken(RC EqualToken) { +TypeAliasDeclSyntaxBuilder::useEqualToken(TokenSyntax EqualToken) { auto Index = cursorIndex(TypeAliasDeclSyntax::Cursor::EqualToken); - TypeAliasLayout[Index] = EqualToken; + TypeAliasLayout[Index] = EqualToken.getRaw(); return *this; } @@ -460,95 +330,76 @@ TypeAliasDeclSyntaxBuilder::useType(TypeSyntax ReferentType) { TypeAliasDeclSyntax TypeAliasDeclSyntaxBuilder::build() const { auto Raw = RawSyntax::make(SyntaxKind::TypeAliasDecl, TypeAliasLayout, SourcePresence::Present); - auto Data = TypeAliasDeclSyntaxData::make(Raw); + auto Data = SyntaxData::make(Raw); return { Data, Data.get() }; } #pragma mark - function-parameter Data -FunctionParameterSyntaxData::FunctionParameterSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : SyntaxData(Raw, Parent, IndexInParent) { +void FunctionParameterSyntax::validate() const { + auto Raw = Data->Raw; assert(Raw->Layout.size() == 8); - syntax_assert_child_token(Raw, FunctionParameterSyntax::Cursor::ExternalName, + syntax_assert_child_token(Raw, Cursor::ExternalName, tok::identifier); - syntax_assert_child_token(Raw, FunctionParameterSyntax::Cursor::LocalName, + syntax_assert_child_token(Raw, Cursor::LocalName, tok::identifier); - syntax_assert_child_token_text(Raw, FunctionParameterSyntax::Cursor::Colon, - tok::colon, ":"); - assert(Raw->getChild(FunctionParameterSyntax::Cursor::Type)->isType()); - syntax_assert_child_token_text(Raw, FunctionParameterSyntax::Cursor::Ellipsis, - tok::identifier, "..."); - syntax_assert_child_token_text(Raw, - FunctionParameterSyntax::Cursor::DefaultEqual, - tok::equal, "="); - assert(Raw->getChild( - FunctionParameterSyntax::Cursor::DefaultExpression)->isExpr()); - syntax_assert_child_token_text(Raw, - FunctionParameterSyntax::Cursor::TrailingComma, - tok::comma, ","); + syntax_assert_child_token_text(Raw, Cursor::Colon, tok::colon, ":"); + assert(Raw->getChild(Cursor::Type)->isType()); + syntax_assert_child_token_text(Raw, Cursor::Ellipsis, tok::identifier, "..."); + syntax_assert_child_token_text(Raw, Cursor::DefaultEqual, tok::equal, "="); + assert(Raw->getChild(Cursor::DefaultExpression)->isExpr()); + syntax_assert_child_token_text(Raw, Cursor::TrailingComma, tok::comma, ","); } -RC -FunctionParameterSyntaxData::make(RC Raw, const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new FunctionParameterSyntaxData { - Raw, Parent, IndexInParent - } - }; -} - -RC FunctionParameterSyntaxData::makeBlank() { +FunctionParameterSyntax FunctionParameterSyntax::makeBlank() { auto Raw = RawSyntax::make(SyntaxKind::FunctionParameter, { - TokenSyntax::missingToken(tok::identifier, ""), - TokenSyntax::missingToken(tok::identifier, ""), - TokenSyntax::missingToken(tok::colon, ":"), + RawTokenSyntax::missingToken(tok::identifier, ""), + RawTokenSyntax::missingToken(tok::identifier, ""), + RawTokenSyntax::missingToken(tok::colon, ":"), RawSyntax::missing(SyntaxKind::MissingType), - TokenSyntax::missingToken(tok::identifier, "..."), - TokenSyntax::missingToken(tok::equal, "="), + RawTokenSyntax::missingToken(tok::identifier, "..."), + RawTokenSyntax::missingToken(tok::equal, "="), RawSyntax::missing(SyntaxKind::MissingExpr), - TokenSyntax::missingToken(tok::comma, ","), + RawTokenSyntax::missingToken(tok::comma, ","), }, SourcePresence::Present); - return make(Raw); + return make(Raw); } #pragma mark - function-parameter API -RC FunctionParameterSyntax::getExternalName() const { - return cast(getRaw()->getChild(Cursor::ExternalName)); +TokenSyntax FunctionParameterSyntax::getExternalName() const { + return { Root, Data->getChild(Cursor::ExternalName).get() }; } FunctionParameterSyntax FunctionParameterSyntax:: -withExternalName(RC NewExternalName) const { - assert(NewExternalName->getTokenKind() == tok::identifier); - return Data->replaceChild(NewExternalName, +withExternalName(TokenSyntax NewExternalName) const { + assert(NewExternalName.getTokenKind() == tok::identifier); + return Data->replaceChild(NewExternalName.getRaw(), Cursor::ExternalName); } -RC FunctionParameterSyntax::getLocalName() const { - return cast(getRaw()->getChild(Cursor::LocalName)); +TokenSyntax FunctionParameterSyntax::getLocalName() const { + return { Root, Data->getChild(Cursor::LocalName).get() }; } FunctionParameterSyntax FunctionParameterSyntax:: -withLocalName(RC NewLocalName) const { - assert(NewLocalName->getTokenKind() == tok::identifier); - return Data->replaceChild(NewLocalName, +withLocalName(TokenSyntax NewLocalName) const { + assert(NewLocalName.getTokenKind() == tok::identifier); + return Data->replaceChild(NewLocalName.getRaw(), Cursor::LocalName); } -RC FunctionParameterSyntax::getColonToken() const { - return cast(getRaw()->getChild(Cursor::Colon)); +TokenSyntax FunctionParameterSyntax::getColonToken() const { + return { Root, Data->getChild(Cursor::Colon).get() }; } FunctionParameterSyntax FunctionParameterSyntax:: -withColonToken(RC NewColonToken) const { +withColonToken(TokenSyntax NewColonToken) const { syntax_assert_token_is(NewColonToken, tok::colon, ":"); - return Data->replaceChild(NewColonToken, + return Data->replaceChild(NewColonToken.getRaw(), Cursor::Colon); } @@ -558,19 +409,7 @@ llvm::Optional FunctionParameterSyntax::getTypeSyntax() const { return llvm::None; } - auto *MyData = getUnsafeData(); - - if (MyData->CachedTypeSyntax) { - return TypeSyntax { Root, MyData->CachedTypeSyntax.get() }; - } - - auto &ChildPtr = *reinterpret_cast*>( - &MyData->CachedTypeSyntax); - - SyntaxData::realizeSyntaxNode(ChildPtr, RawType, MyData, - cursorIndex(Cursor::Type)); - - return TypeSyntax { Root, MyData->CachedTypeSyntax.get() }; + return TypeSyntax { Root, Data->getChild(Cursor::Type).get() }; } FunctionParameterSyntax FunctionParameterSyntax:: @@ -584,36 +423,24 @@ withTypeSyntax(llvm::Optional NewType) const { NewType.getValue().getRaw(), Cursor::Type); } -RC FunctionParameterSyntax::getEqualToken() const { - return cast(getRaw()->getChild(Cursor::DefaultEqual)); +TokenSyntax FunctionParameterSyntax::getEqualToken() const { + return { Root, Data->getChild(Cursor::DefaultEqual).get() }; } FunctionParameterSyntax FunctionParameterSyntax:: -withEqualToken(RC NewEqualToken) const { - assert(NewEqualToken->getTokenKind() == tok::equal); - return Data->replaceChild(NewEqualToken, +withEqualToken(TokenSyntax NewEqualToken) const { + assert(NewEqualToken.getTokenKind() == tok::equal); + return Data->replaceChild(NewEqualToken.getRaw(), Cursor::DefaultEqual); } llvm::Optional FunctionParameterSyntax::getDefaultValue() const { - auto RawExpr = getRaw()->getChild(Cursor::DefaultExpression); - if (RawExpr->isMissing()) { - return llvm::None; - } + auto RawExpr = getRaw()->getChild(Cursor::DefaultExpression); + if (RawExpr->isMissing()) { + return llvm::None; + } - auto *MyData = getUnsafeData(); - - if (MyData->CachedTypeSyntax) { - return ExprSyntax { Root, MyData->CachedDefaultValue.get() }; - } - - auto &ChildPtr = *reinterpret_cast*>( - &MyData->CachedDefaultValue); - - SyntaxData::realizeSyntaxNode(ChildPtr, RawExpr, MyData, - cursorIndex(Cursor::DefaultExpression)); - - return ExprSyntax { Root, MyData->CachedDefaultValue.get() }; + return ExprSyntax { Root, Data->getChild(Cursor::DefaultExpression).get() }; } FunctionParameterSyntax FunctionParameterSyntax:: @@ -628,101 +455,78 @@ withDefaultValue(llvm::Optional NewDefaultValue) const { NewDefaultValue.getValue().getRaw(), Cursor::DefaultExpression); } -RC FunctionParameterSyntax::getTrailingComma() const { - return cast(getRaw()->getChild(Cursor::TrailingComma)); +TokenSyntax FunctionParameterSyntax::getTrailingComma() const { + return { Root, Data->getChild(Cursor::TrailingComma).get() }; } FunctionParameterSyntax FunctionParameterSyntax:: -withTrailingComma(RC NewTrailingComma) const { +withTrailingComma(TokenSyntax NewTrailingComma) const { syntax_assert_token_is(NewTrailingComma, tok::comma, ","); - return Data->replaceChild(NewTrailingComma, + return Data->replaceChild(NewTrailingComma.getRaw(), Cursor::TrailingComma); } #pragma mark - function-signature Data -FunctionSignatureSyntaxData:: -FunctionSignatureSyntaxData(const RC Raw, - const SyntaxData *Parent, - const CursorIndex IndexInParent) - : SyntaxData(Raw, Parent, IndexInParent) { +void FunctionSignatureSyntax::validate() const { + auto Raw = Data->Raw; assert(Raw->Layout.size() == 7); syntax_assert_child_token_text(Raw, - FunctionSignatureSyntax::Cursor::LeftParen, + Cursor::LeftParen, tok::l_paren, "("); - assert(Raw->getChild(FunctionSignatureSyntax::Cursor::ParameterList)->Kind == + assert(Raw->getChild(Cursor::ParameterList)->Kind == SyntaxKind::FunctionParameterList); syntax_assert_child_token_text(Raw, - FunctionSignatureSyntax::Cursor::RightParen, + Cursor::RightParen, tok::r_paren, ")"); #ifndef NDEBUG - auto ThrowsRethrows = cast( - Raw->getChild(FunctionSignatureSyntax::Cursor::ThrowsOrRethrows)); - assert(cast(ThrowsRethrows)->getTokenKind() == tok::kw_throws || - cast(ThrowsRethrows)->getTokenKind() == tok::kw_rethrows); + auto ThrowsRethrows = cast( + Raw->getChild(Cursor::ThrowsOrRethrows)); + assert(ThrowsRethrows->getTokenKind() == tok::kw_throws || + ThrowsRethrows->getTokenKind() == tok::kw_rethrows); #endif - syntax_assert_child_token_text(Raw, FunctionSignatureSyntax::Cursor::Arrow, + syntax_assert_child_token_text(Raw, Cursor::Arrow, tok::arrow, "->"); syntax_assert_child_kind(Raw, - FunctionSignatureSyntax::Cursor::ReturnTypeAttributes, - SyntaxKind::TypeAttributes); - assert(Raw->getChild(FunctionSignatureSyntax::Cursor::ReturnType)->isType()); + Cursor::ReturnTypeAttributes, + SyntaxKind::TypeAttributes); + assert(Raw->getChild(Cursor::ReturnType)->isType()); } -RC -FunctionSignatureSyntaxData::make(RC Raw, const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new FunctionSignatureSyntaxData { - Raw, Parent, IndexInParent - } - }; -} - -RC FunctionSignatureSyntaxData::makeBlank() { +FunctionSignatureSyntax FunctionSignatureSyntax::makeBlank() { auto Raw = RawSyntax::make(SyntaxKind::FunctionSignature, { - TokenSyntax::missingToken(tok::l_paren, "("), + RawTokenSyntax::missingToken(tok::l_paren, "("), RawSyntax::missing(SyntaxKind::FunctionParameterList), - TokenSyntax::missingToken(tok::r_paren, ")"), - TokenSyntax::missingToken(tok::kw_throws, "throws"), - TokenSyntax::missingToken(tok::arrow, "->"), + RawTokenSyntax::missingToken(tok::r_paren, ")"), + RawTokenSyntax::missingToken(tok::kw_throws, "throws"), + RawTokenSyntax::missingToken(tok::arrow, "->"), RawSyntax::missing(SyntaxKind::TypeAttributes), RawSyntax::missing(SyntaxKind::MissingType), }, SourcePresence::Present); - return make(Raw); + return make(Raw); } #pragma mark - function-signature API -RC FunctionSignatureSyntax::getLeftParenToken() const { - return cast(getRaw()->getChild(Cursor::LeftParen)); +TokenSyntax FunctionSignatureSyntax::getLeftParenToken() const { + return { Root, Data->getChild(Cursor::LeftParen).get() }; } FunctionSignatureSyntax FunctionSignatureSyntax:: -withLeftParenToken(RC NewLeftParen) const { +withLeftParenToken(TokenSyntax NewLeftParen) const { syntax_assert_token_is(NewLeftParen, tok::l_paren, "("); - return Data->replaceChild(NewLeftParen, + return Data->replaceChild(NewLeftParen.getRaw(), Cursor::LeftParen); } FunctionParameterListSyntax FunctionSignatureSyntax::getParameterList() const { - auto RawList = getRaw()->getChild(Cursor::ParameterList); - - auto *MyData = getUnsafeData(); - - auto &ChildPtr = *reinterpret_cast*>( - &MyData->CachedParameterList); - - SyntaxData::realizeSyntaxNode(ChildPtr, RawList, - MyData, cursorIndex(Cursor::ParameterList)); - return FunctionParameterListSyntax { Root, - MyData->CachedParameterList.get() + Data->getChild(Cursor::ParameterList).get() }; } @@ -732,73 +536,64 @@ withParameterList(FunctionParameterListSyntax NewParameterList) const { Cursor::ParameterList); } -RC FunctionSignatureSyntax::getRightParenToken() const { - return cast(getRaw()->getChild(Cursor::RightParen)); +TokenSyntax FunctionSignatureSyntax::getRightParenToken() const { + return { Root, Data->getChild(Cursor::RightParen).get() }; } FunctionSignatureSyntax FunctionSignatureSyntax:: -withRightParenToken(RC NewRightParen) const { +withRightParenToken(TokenSyntax NewRightParen) const { syntax_assert_token_is(NewRightParen, tok::r_paren, ")"); - return Data->replaceChild(NewRightParen, + return Data->replaceChild(NewRightParen.getRaw(), Cursor::RightParen); } -RC FunctionSignatureSyntax::getThrowsToken() const { - auto Throw = cast(getRaw()->getChild(Cursor::ThrowsOrRethrows)); - if (Throw->getTokenKind() != tok::kw_throws) { +TokenSyntax FunctionSignatureSyntax::getThrowsToken() const { + auto Throw = cast( + getRaw()->getChild(Cursor::ThrowsOrRethrows)); + if (Throw->isNot(tok::kw_throws)) { return TokenSyntax::missingToken(tok::kw_throws, "throws"); } - return Throw; + return { Root, Data->getChild(Cursor::ThrowsOrRethrows).get() }; } FunctionSignatureSyntax FunctionSignatureSyntax:: -withThrowsToken(RC NewThrowsToken) const { +withThrowsToken(TokenSyntax NewThrowsToken) const { syntax_assert_token_is(NewThrowsToken, tok::kw_throws, "throws"); - return Data->replaceChild(NewThrowsToken, + return Data->replaceChild(NewThrowsToken.getRaw(), Cursor::ThrowsOrRethrows); } -RC FunctionSignatureSyntax::getRethrowsToken() const { - auto Rethrow = cast( +TokenSyntax FunctionSignatureSyntax::getRethrowsToken() const { + auto Rethrow = cast( getRaw()->getChild(Cursor::ThrowsOrRethrows)); - if (Rethrow->getTokenKind() != tok::kw_rethrows) { + if (Rethrow->isNot(tok::kw_rethrows)) { return TokenSyntax::missingToken(tok::kw_rethrows, "rethrows"); } - return Rethrow; + return { Root, Data->getChild(Cursor::ThrowsOrRethrows).get() }; } FunctionSignatureSyntax FunctionSignatureSyntax:: -withRethrowsToken(RC NewRethrowsToken) const { +withRethrowsToken(TokenSyntax NewRethrowsToken) const { syntax_assert_token_is(NewRethrowsToken, tok::kw_rethrows, "rethrows"); - return Data->replaceChild(NewRethrowsToken, + return Data->replaceChild(NewRethrowsToken.getRaw(), Cursor::ThrowsOrRethrows); } -RC FunctionSignatureSyntax::getArrowToken() const { - return cast(getRaw()->getChild(Cursor::Arrow)); +TokenSyntax FunctionSignatureSyntax::getArrowToken() const { + return { Root, Data->getChild(Cursor::Arrow).get() }; } FunctionSignatureSyntax FunctionSignatureSyntax:: -withArrowToken(RC NewArrowToken) const { +withArrowToken(TokenSyntax NewArrowToken) const { syntax_assert_token_is(NewArrowToken, tok::arrow, "->"); - return Data->replaceChild(NewArrowToken, + return Data->replaceChild(NewArrowToken.getRaw(), Cursor::Arrow); } TypeAttributesSyntax FunctionSignatureSyntax::getReturnTypeAttributes() const { - auto RawAttrs = getRaw()->getChild(Cursor::ReturnTypeAttributes); - - auto *MyData = getUnsafeData(); - - auto &ChildPtr = *reinterpret_cast*>( - &MyData->CachedReturnTypeAttributes); - - SyntaxData::realizeSyntaxNode(ChildPtr, RawAttrs, - MyData, cursorIndex(Cursor::ReturnTypeAttributes)); - return TypeAttributesSyntax { Root, - MyData->CachedReturnTypeAttributes.get() + Data->getChild(Cursor::ReturnTypeAttributes).get() }; } @@ -809,19 +604,9 @@ withReturnTypeAttributes(TypeAttributesSyntax NewAttributes) const { } TypeSyntax FunctionSignatureSyntax::getReturnTypeSyntax() const { - auto RawType = getRaw()->getChild(Cursor::ReturnType); - - auto *MyData = getUnsafeData(); - - auto &ChildPtr = *reinterpret_cast*>( - &MyData->CachedReturnTypeSyntax); - - SyntaxData::realizeSyntaxNode(ChildPtr, RawType, - MyData, cursorIndex(Cursor::ReturnType)); - return TypeSyntax { Root, - MyData->CachedReturnTypeSyntax.get() + Data->getChild(Cursor::ReturnType).get() }; } @@ -833,11 +618,8 @@ withReturnTypeSyntax(TypeSyntax NewReturnTypeSyntax) const { #pragma mark - function-declaration-data -FunctionDeclSyntaxData:: -FunctionDeclSyntaxData(const RC Raw, - const SyntaxData *Parent, - const CursorIndex IndexInParent) - : SyntaxData(Raw, Parent, IndexInParent) { +void FunctionDeclSyntax::validate() const { + auto Raw = Data->Raw; assert(Raw->Kind == SyntaxKind::FunctionDecl); assert(Raw->Layout.size() == 8); syntax_assert_child_kind(Raw, FunctionDeclSyntax::Cursor::Attributes, @@ -859,46 +641,26 @@ FunctionDeclSyntaxData(const RC Raw, SyntaxKind::CodeBlockStmt); } -RC FunctionDeclSyntaxData::make(const RC Raw, - const SyntaxData *Parent, - const CursorIndex IndexInParent) { - return RC { - new FunctionDeclSyntaxData { - Raw, Parent, IndexInParent - } - }; -} - -RC FunctionDeclSyntaxData::makeBlank() { +FunctionDeclSyntax FunctionDeclSyntax::makeBlank() { auto Raw = RawSyntax::make(SyntaxKind::FunctionDecl, { RawSyntax::missing(SyntaxKind::TypeAttributes), RawSyntax::missing(SyntaxKind::DeclModifierList), - TokenSyntax::missingToken(tok::kw_func, "func"), - TokenSyntax::missingToken(tok::identifier, ""), + RawTokenSyntax::missingToken(tok::kw_func, "func"), + RawTokenSyntax::missingToken(tok::identifier, ""), RawSyntax::missing(SyntaxKind::GenericParameterClause), RawSyntax::missing(SyntaxKind::FunctionSignature), RawSyntax::missing(SyntaxKind::GenericWhereClause), RawSyntax::missing(SyntaxKind::CodeBlockStmt), }, SourcePresence::Present); - return make(Raw); + return make(Raw); } #pragma mark - function-declaration-API TypeAttributesSyntax FunctionDeclSyntax::getAttributes() const { - auto RawAttrs = getRaw()->getChild(Cursor::Attributes); - - auto *MyData = getUnsafeData(); - - auto &ChildPtr = *reinterpret_cast*>( - &MyData->CachedAttributes); - - SyntaxData::realizeSyntaxNode(ChildPtr, RawAttrs, MyData, - cursorIndex(Cursor::Attributes)); - - return { Root, MyData->CachedAttributes.get() }; + return { Root, Data->getChild(Cursor::Attributes).get() }; } FunctionDeclSyntax @@ -908,17 +670,7 @@ FunctionDeclSyntax::withAttributes(TypeAttributesSyntax NewAttributes) const { } DeclModifierListSyntax FunctionDeclSyntax::getModifiers() const { - auto RawModifiers = getRaw()->getChild(Cursor::Attributes); - - auto *MyData = getUnsafeData(); - - auto &ChildPtr = *reinterpret_cast*>( - &MyData->CachedModifiers); - - SyntaxData::realizeSyntaxNode(ChildPtr, RawModifiers, - MyData, cursorIndex(Cursor::Modifiers)); - - return { Root, MyData->CachedModifiers.get() }; + return { Root, Data->getChild(Cursor::Modifiers).get() }; } FunctionDeclSyntax @@ -927,50 +679,40 @@ FunctionDeclSyntax::withModifiers(DeclModifierListSyntax NewModifiers) const { Cursor::Modifiers); } -RC FunctionDeclSyntax::getFuncKeyword() const { - return cast(getRaw()->getChild(Cursor::FuncKeyword)); +TokenSyntax FunctionDeclSyntax::getFuncKeyword() const { + return { Root, Data->getChild(Cursor::FuncKeyword).get() }; } FunctionDeclSyntax -FunctionDeclSyntax::withFuncKeyword(RC NewFuncKeyword) const { +FunctionDeclSyntax::withFuncKeyword(TokenSyntax NewFuncKeyword) const { syntax_assert_token_is(NewFuncKeyword, tok::kw_func, "func"); - return Data->replaceChild(NewFuncKeyword, + return Data->replaceChild(NewFuncKeyword.getRaw(), Cursor::FuncKeyword); - } -RC FunctionDeclSyntax::getIdentifier() const { - return cast(getRaw()->getChild(Cursor::Identifier)); +TokenSyntax FunctionDeclSyntax::getIdentifier() const { + return { Root, Data->getChild(Cursor::Identifier).get() }; } FunctionDeclSyntax -FunctionDeclSyntax::withIdentifier(RC NewIdentifier) const { - assert(NewIdentifier->getTokenKind() == tok::identifier); - return Data->replaceChild(NewIdentifier, +FunctionDeclSyntax::withIdentifier(TokenSyntax NewIdentifier) const { + assert(NewIdentifier.getTokenKind() == tok::identifier); + return Data->replaceChild(NewIdentifier.getRaw(), Cursor::Identifier); } llvm::Optional FunctionDeclSyntax::getGenericParameterClause() const { - auto RawGenericParams = getRaw()->getChild(Cursor::Attributes); + auto RawGenericParams = getRaw()->getChild(Cursor::GenericParameterClause); if (RawGenericParams->isMissing()) { return llvm::None; } - - auto *MyData = getUnsafeData(); - - auto &ChildPtr = *reinterpret_cast*>( - &MyData->CachedGenericParams); - - SyntaxData::realizeSyntaxNode(ChildPtr, - RawGenericParams, MyData, cursorIndex(Cursor::GenericParameterClause)); - - GenericParameterClauseSyntax Params { - Root, - MyData->CachedGenericParams.get() + return llvm::Optional { + GenericParameterClauseSyntax { + Root, + Data->getChild(Cursor::GenericParameterClause).get() + } }; - - return Params; } FunctionDeclSyntax FunctionDeclSyntax::withGenericParameterClause( @@ -984,17 +726,7 @@ FunctionDeclSyntax FunctionDeclSyntax::withGenericParameterClause( } FunctionSignatureSyntax FunctionDeclSyntax::getSignature() const { - auto RawSig = getRaw()->getChild(Cursor::Attributes); - - auto *MyData = getUnsafeData(); - - auto &ChildPtr = *reinterpret_cast*>( - &MyData->CachedSignature); - - SyntaxData::realizeSyntaxNode(ChildPtr, RawSig, - MyData, cursorIndex(Cursor::Signature)); - - return { Root, MyData->CachedSignature.get() }; + return { Root, Data->getChild(Cursor::Signature).get() }; } FunctionDeclSyntax @@ -1008,21 +740,10 @@ llvm::Optional FunctionDeclSyntax::getBody() const { if (RawBody->isMissing()) { return llvm::None; } - - auto *MyData = getUnsafeData(); - - auto &ChildPtr = *reinterpret_cast*>( - &MyData->CachedBody); - - SyntaxData::realizeSyntaxNode(ChildPtr, - RawBody, MyData, cursorIndex(Cursor::Body)); - CodeBlockStmtSyntax Body { - Root, - MyData->CachedBody.get() + return llvm::Optional { + CodeBlockStmtSyntax { Root, Data->getChild(Cursor::Body).get() } }; - - return Body; } FunctionDeclSyntax FunctionDeclSyntax:: diff --git a/lib/Syntax/ExprSyntax.cpp b/lib/Syntax/ExprSyntax.cpp index 9f3aa6e0595..f2bf284b0c8 100644 --- a/lib/Syntax/ExprSyntax.cpp +++ b/lib/Syntax/ExprSyntax.cpp @@ -16,161 +16,80 @@ using namespace swift; using namespace swift::syntax; -#pragma mark - expression Data - -RC ExprSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new ExprSyntaxData { - Raw, Parent, IndexInParent - } - }; -} - -RC ExprSyntaxData::makeBlank() { - return make(RawSyntax::missing(SyntaxKind::MissingExpr)); -} - #pragma mark - expression API -ExprSyntax::ExprSyntax(const RC Root, const ExprSyntaxData *Data) - : Syntax(Root, Data) {} - -#pragma mark - unknown-expression Data - -UnknownExprSyntaxData::UnknownExprSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : UnknownSyntaxData(Raw, Parent, IndexInParent) { - assert(Raw->Kind == SyntaxKind::UnknownExpr); -} - -RC -UnknownExprSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - auto UnknownRaw = RawSyntax::make(SyntaxKind::UnknownExpr, Raw->Layout, - Raw->Presence); - return RC { - new UnknownExprSyntaxData { - UnknownRaw, Parent, IndexInParent - } - }; +ExprSyntax ExprSyntax::makeBlank() { + return make(RawSyntax::missing(SyntaxKind::MissingExpr)); } #pragma mark - unknown-expression API -UnknownExprSyntax::UnknownExprSyntax(const RC Root, - const UnknownExprSyntaxData *Data) - : UnknownSyntax(Root, Data) {} - -#pragma mark - integer-literal-expression Data - -IntegerLiteralExprSyntaxData:: -IntegerLiteralExprSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : ExprSyntaxData(Raw, Parent, IndexInParent) { - assert(Raw->Kind == SyntaxKind::IntegerLiteralExpr); - assert(Raw->Layout.size() == 2); - syntax_assert_child_token(Raw, IntegerLiteralExprSyntax::Cursor::Sign, - tok::oper_prefix); - syntax_assert_child_token(Raw, IntegerLiteralExprSyntax::Cursor::Digits, - tok::integer_literal); -} - -RC -IntegerLiteralExprSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new IntegerLiteralExprSyntaxData { - Raw, Parent, IndexInParent - } - }; -} -RC IntegerLiteralExprSyntaxData::makeBlank() { - auto Raw = RawSyntax::make(SyntaxKind::IntegerLiteralExpr, - { - TokenSyntax::missingToken(tok::oper_prefix, ""), - TokenSyntax::missingToken(tok::integer_literal, "") - }, - SourcePresence::Present); - return make(Raw); +void UnknownExprSyntax::validate() const { + assert(Data->Raw->Kind == SyntaxKind::UnknownExpr); } #pragma mark - integer-literal-expression API -IntegerLiteralExprSyntax:: -IntegerLiteralExprSyntax(const RC Root, - const IntegerLiteralExprSyntaxData *Data) - : ExprSyntax(Root, Data) {} +void IntegerLiteralExprSyntax::validate() const { + assert(Data->Raw->Kind == SyntaxKind::IntegerLiteralExpr); + assert(Data->Raw->Layout.size() == 2); + syntax_assert_child_token(Data->Raw, Cursor::Sign, + tok::oper_prefix); + syntax_assert_child_token(Data->Raw, Cursor::Digits, + tok::integer_literal); +} + +IntegerLiteralExprSyntax IntegerLiteralExprSyntax::makeBlank() { + auto Raw = RawSyntax::make(SyntaxKind::IntegerLiteralExpr, + { + RawTokenSyntax::missingToken(tok::oper_prefix, ""), + RawTokenSyntax::missingToken(tok::integer_literal, "") + }, + SourcePresence::Present); + return make(Raw); +} IntegerLiteralExprSyntax -IntegerLiteralExprSyntax::withDigits(RC NewDigits) const { - assert(NewDigits->getTokenKind() == tok::integer_literal); - return Data->replaceChild(NewDigits, +IntegerLiteralExprSyntax::withDigits(TokenSyntax NewDigits) const { + assert(NewDigits.getTokenKind() == tok::integer_literal); + return Data->replaceChild(NewDigits.getRaw(), Cursor::Digits); } IntegerLiteralExprSyntax -IntegerLiteralExprSyntax::withSign(RC NewSign) - const { - assert(NewSign->getTokenKind() == tok::oper_prefix); - return Data->replaceChild(NewSign, Cursor::Sign); -} - -#pragma mark - symbolic-reference Data - -SymbolicReferenceExprSyntaxData:: -SymbolicReferenceExprSyntaxData(RC Raw, const SyntaxData *Parent, - CursorIndex IndexInParent) - : ExprSyntaxData(Raw, Parent, IndexInParent) { - assert(Raw->Layout.size() == 2); - syntax_assert_child_token(Raw, - SymbolicReferenceExprSyntax::Cursor::Identifier, tok::identifier); - syntax_assert_child_kind(Raw, - SymbolicReferenceExprSyntax::Cursor::GenericArgumentClause, - SyntaxKind::GenericArgumentClause); -} - -RC -SymbolicReferenceExprSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new SymbolicReferenceExprSyntaxData { - Raw, Parent, IndexInParent - } - }; -} - -RC -SymbolicReferenceExprSyntaxData::makeBlank() { - auto Raw = RawSyntax::make(SyntaxKind::SymbolicReferenceExpr, - { - TokenSyntax::missingToken(tok::identifier, ""), - RawSyntax::missing(SyntaxKind::GenericArgumentClause), - }, - SourcePresence::Present); - return make(Raw); +IntegerLiteralExprSyntax::withSign(TokenSyntax NewSign) const { + assert(NewSign.getTokenKind() == tok::oper_prefix); + return Data->replaceChild(NewSign.getRaw(), + Cursor::Sign); } #pragma mark - symbolic-reference API -SymbolicReferenceExprSyntax:: -SymbolicReferenceExprSyntax(const RC Root, const DataType *Data) - : ExprSyntax(Root, Data) {} +void SymbolicReferenceExprSyntax::validate() const { + assert(Data->Raw->Layout.size() == 2); + syntax_assert_child_token(Data->Raw, Cursor::Identifier, tok::identifier); + syntax_assert_child_kind(Data->Raw, Cursor::GenericArgumentClause, + SyntaxKind::GenericArgumentClause); +} -RC SymbolicReferenceExprSyntax::getIdentifier() const { - return cast(getRaw()->getChild(Cursor::Identifier)); +SymbolicReferenceExprSyntax SymbolicReferenceExprSyntax::makeBlank() { + auto Raw = RawSyntax::make(SyntaxKind::SymbolicReferenceExpr, + { + RawTokenSyntax::missingToken(tok::identifier, ""), + RawSyntax::missing(SyntaxKind::GenericArgumentClause), + }, + SourcePresence::Present); + return make(Raw); +} + +TokenSyntax SymbolicReferenceExprSyntax::getIdentifier() const { + return { Root, Data->getChild(Cursor::Identifier).get() }; } SymbolicReferenceExprSyntax SymbolicReferenceExprSyntax:: -withIdentifier(RC NewIdentifier) const { - assert(NewIdentifier->getTokenKind() == tok::identifier); - return Data->replaceChild(NewIdentifier, +withIdentifier(TokenSyntax NewIdentifier) const { + assert(NewIdentifier.getTokenKind() == tok::identifier); + return Data->replaceChild(NewIdentifier.getRaw(), Cursor::Identifier); } @@ -181,17 +100,10 @@ SymbolicReferenceExprSyntax::getGenericArgumentClause() const { return llvm::None; } - auto *MyData = getUnsafeData(); - auto &ChildPtr = *reinterpret_cast*>( - &MyData->CachedGenericArgClause); - SyntaxData::realizeSyntaxNode(ChildPtr, - RawClause, MyData, - cursorIndex(Cursor::GenericArgumentClause)); - return llvm::Optional { GenericArgumentClauseSyntax { Root, - MyData->CachedGenericArgClause.get() + Data->getChild(Cursor::GenericArgumentClause).get() } }; } @@ -204,72 +116,51 @@ withGenericArgumentClause(GenericArgumentClauseSyntax NewGenericArgs) const { #pragma mark - function-call-argument Data -FunctionCallArgumentSyntaxData:: -FunctionCallArgumentSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : SyntaxData(Raw, Parent, IndexInParent) { - syntax_assert_child_token(Raw, FunctionCallArgumentSyntax::Cursor::Label, - tok::identifier); - syntax_assert_child_token_text(Raw, - FunctionCallArgumentSyntax::Cursor::Colon, - tok::colon, ":"); - assert( - Raw->getChild(FunctionCallArgumentSyntax::Cursor::Expression)->isExpr()); +void FunctionCallArgumentSyntax::validate() const { + syntax_assert_child_token(Data->Raw, Cursor::Label, + tok::identifier); + syntax_assert_child_token_text(Data->Raw, Cursor::Colon, + tok::colon, ":"); + assert(Data->Raw->getChild(Cursor::Expression)->isExpr()); - syntax_assert_child_token_text(Raw, - FunctionCallArgumentSyntax::Cursor::Comma, - tok::comma, ","); + syntax_assert_child_token_text(Data->Raw, + Cursor::Comma, + tok::comma, ","); } -RC -FunctionCallArgumentSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new FunctionCallArgumentSyntaxData { - Raw, Parent, IndexInParent - } - }; -} - -RC FunctionCallArgumentSyntaxData::makeBlank() { +FunctionCallArgumentSyntax FunctionCallArgumentSyntax::makeBlank() { auto Raw = RawSyntax::make(SyntaxKind::FunctionCallArgument, { - TokenSyntax::missingToken(tok::identifier, ""), - TokenSyntax::missingToken(tok::colon, ":"), + RawTokenSyntax::missingToken(tok::identifier, ""), + RawTokenSyntax::missingToken(tok::colon, ":"), RawSyntax::missing(SyntaxKind::MissingExpr), - TokenSyntax::missingToken(tok::comma, ",") + RawTokenSyntax::missingToken(tok::comma, ",") }, SourcePresence::Present); - return make(Raw); + return make(Raw); } #pragma mark - function-call-argument API -FunctionCallArgumentSyntax:: -FunctionCallArgumentSyntax(const RC Root, const DataType *Data) - : Syntax(Root, Data) {} - -RC FunctionCallArgumentSyntax::getLabel() const { - return cast(getRaw()->getChild(Cursor::Label)); +TokenSyntax FunctionCallArgumentSyntax::getLabel() const { + return { Root, Data->getChild(Cursor::Label).get() }; } FunctionCallArgumentSyntax -FunctionCallArgumentSyntax::withLabel(RC NewLabel) const { - assert(NewLabel->getTokenKind() == tok::identifier); - return Data->replaceChild(NewLabel, +FunctionCallArgumentSyntax::withLabel(TokenSyntax NewLabel) const { + assert(NewLabel.getTokenKind() == tok::identifier); + return Data->replaceChild(NewLabel.getRaw(), Cursor::Label); } -RC FunctionCallArgumentSyntax::getColonToken() const { - return cast(getRaw()->getChild(Cursor::Colon)); +TokenSyntax FunctionCallArgumentSyntax::getColonToken() const { + return { Root, Data->getChild(Cursor::Colon).get() }; } FunctionCallArgumentSyntax -FunctionCallArgumentSyntax::withColonToken(RC NewColon) const { +FunctionCallArgumentSyntax::withColonToken(TokenSyntax NewColon) const { syntax_assert_token_is(NewColon, tok::colon, ":"); - return Data->replaceChild(NewColon, + return Data->replaceChild(NewColon.getRaw(), Cursor::Colon); } @@ -279,16 +170,10 @@ llvm::Optional FunctionCallArgumentSyntax::getExpression() const { if (RawExpression->isMissing()) { return llvm::None; } - - auto *MyData = getUnsafeData(); - - auto &ChildPtr = *reinterpret_cast*>( - &MyData->CachedExpression); - - SyntaxData::realizeSyntaxNode(ChildPtr, RawExpression, MyData, - cursorIndex(Cursor::Expression)); - return ExprSyntax { Root, MyData->CachedExpression.get() }; + return llvm::Optional { + ExprSyntax { Root, Data->getChild(Cursor::Expression).get() } + }; } FunctionCallArgumentSyntax @@ -297,87 +182,50 @@ FunctionCallArgumentSyntax::withExpression(ExprSyntax NewExpression) const { Cursor::Expression); } -RC FunctionCallArgumentSyntax::getTrailingComma() const { - return cast(getRaw()->getChild(Cursor::Comma)); +TokenSyntax FunctionCallArgumentSyntax::getTrailingComma() const { + return { Root, Data->getChild(Cursor::Comma).get() }; } FunctionCallArgumentSyntax FunctionCallArgumentSyntax:: -withTrailingComma(RC NewTrailingComma) const { +withTrailingComma(TokenSyntax NewTrailingComma) const { syntax_assert_token_is(NewTrailingComma, tok::comma, ","); - return Data->replaceChild(NewTrailingComma, - FunctionCallArgumentSyntax::Cursor::Comma); + return Data->replaceChild( + NewTrailingComma.getRaw(), Cursor::Comma); } -#pragma mark - function-call-argument-list API - -FunctionCallArgumentListSyntax:: -FunctionCallArgumentListSyntax(const RC Root, - const DataType *Data) - : SyntaxCollection(Root, Data) {} - #pragma mark - function-call-expression Data -RC CachedArgumentList; - -FunctionCallExprSyntaxData::FunctionCallExprSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : ExprSyntaxData(Raw, Parent, IndexInParent) { - assert(Raw->Layout.size() == 4); - assert(Raw->getChild(FunctionCallExprSyntax::Cursor::CalledExpression) +void FunctionCallExprSyntax::validate() const { + auto Raw = Data->Raw; + assert(Raw->getChild(Cursor::CalledExpression) ->isExpr()); - syntax_assert_child_token_text(Raw, FunctionCallExprSyntax::Cursor::LeftParen, + syntax_assert_child_token_text(Raw, Cursor::LeftParen, tok::l_paren, "("); - syntax_assert_child_kind(Raw, FunctionCallExprSyntax::Cursor::ArgumentList, + syntax_assert_child_kind(Raw, Cursor::ArgumentList, SyntaxKind::FunctionCallArgumentList); syntax_assert_child_token_text(Raw, - FunctionCallExprSyntax::Cursor::RightParen, + Cursor::RightParen, tok::r_paren, ")"); } -RC -FunctionCallExprSyntaxData::make(RC Raw, const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new FunctionCallExprSyntaxData { - Raw, Parent, IndexInParent - } - }; -} - -RC FunctionCallExprSyntaxData::makeBlank() { +FunctionCallExprSyntax FunctionCallExprSyntax::makeBlank() { auto Raw = RawSyntax::make(SyntaxKind::FunctionCallExpr, { RawSyntax::missing(SyntaxKind::MissingExpr), - TokenSyntax::missingToken(tok::l_paren, "("), + RawTokenSyntax::missingToken(tok::l_paren, "("), RawSyntax::missing(SyntaxKind::FunctionCallArgumentList), - TokenSyntax::missingToken(tok::r_paren, ")"), + RawTokenSyntax::missingToken(tok::r_paren, ")"), }, SourcePresence::Present); - return make(Raw); + return make(Raw); } - #pragma mark - function-call-expression API -FunctionCallExprSyntax::FunctionCallExprSyntax(const RC Root, - const DataType *Data) - : ExprSyntax(Root, Data) {} - ExprSyntax FunctionCallExprSyntax::getCalledExpression() const { - auto RawArg = getRaw()->getChild(Cursor::CalledExpression); - - auto *MyData = getUnsafeData(); - - auto &ChildPtr = *reinterpret_cast*>( - &MyData->CachedCalledExpression); - - SyntaxData::realizeSyntaxNode( - ChildPtr, RawArg, MyData, cursorIndex(Cursor::CalledExpression)); - - return ExprSyntax { + return { Root, - MyData->CachedCalledExpression.get(), + Data->getChild(Cursor::CalledExpression).get(), }; } @@ -387,31 +235,21 @@ withCalledExpression(ExprSyntax NewBaseExpression) const { Cursor::CalledExpression); } -RC FunctionCallExprSyntax::getLeftParen() const { - return cast(getRaw()->getChild(Cursor::LeftParen)); +TokenSyntax FunctionCallExprSyntax::getLeftParen() const { + return { Root, Data->getChild(Cursor::LeftParen).get() }; } FunctionCallExprSyntax -FunctionCallExprSyntax::withLeftParen(RC NewLeftParen) const { +FunctionCallExprSyntax::withLeftParen(TokenSyntax NewLeftParen) const { syntax_assert_token_is(NewLeftParen, tok::l_paren, "("); - return Data->replaceChild(NewLeftParen, + return Data->replaceChild(NewLeftParen.getRaw(), Cursor::LeftParen); } FunctionCallArgumentListSyntax FunctionCallExprSyntax::getArgumentList() const { - auto RawArg = getRaw()->getChild(Cursor::ArgumentList); - - auto *MyData = getUnsafeData(); - - auto &ChildPtr = *reinterpret_cast*>( - &MyData->CachedArgumentList); - - SyntaxData::realizeSyntaxNode( - ChildPtr, RawArg, MyData, cursorIndex(Cursor::ArgumentList)); - return FunctionCallArgumentListSyntax { Root, - MyData->CachedArgumentList.get(), + Data->getChild(Cursor::ArgumentList).get(), }; } @@ -421,29 +259,28 @@ withArgumentList(FunctionCallArgumentListSyntax NewArgumentList) const { Cursor::ArgumentList); } -RC FunctionCallExprSyntax::getRightParen() const { - return cast(getRaw()->getChild(Cursor::RightParen)); +TokenSyntax FunctionCallExprSyntax::getRightParen() const { + return { Root, Data->getChild(Cursor::RightParen).get() }; } FunctionCallExprSyntax -FunctionCallExprSyntax::withRightParen(RC NewRightParen) const { +FunctionCallExprSyntax::withRightParen(TokenSyntax NewRightParen) const { syntax_assert_token_is(NewRightParen, tok::r_paren, ")"); - return Data->replaceChild(NewRightParen, + return Data->replaceChild(NewRightParen.getRaw(), Cursor::RightParen); } #pragma mark - function-call-expression Builder FunctionCallExprSyntaxBuilder::FunctionCallExprSyntaxBuilder() - : CallLayout(FunctionCallExprSyntaxData::makeBlank()->getRaw()->Layout), - ListLayout( - FunctionCallArgumentListSyntaxData::makeBlank()->getRaw()->Layout) {} + : CallLayout(FunctionCallExprSyntax::makeBlank().getRaw()->Layout), + ListLayout(FunctionCallArgumentListSyntax::makeBlank().getRaw()->Layout) {} FunctionCallExprSyntaxBuilder & -FunctionCallExprSyntaxBuilder::useLeftParen(RC LeftParen) { +FunctionCallExprSyntaxBuilder::useLeftParen(TokenSyntax LeftParen) { syntax_assert_token_is(LeftParen, tok::l_paren, "("); CallLayout[cursorIndex(FunctionCallExprSyntax::Cursor::LeftParen)] - = LeftParen; + = LeftParen.getRaw(); return *this; } @@ -461,10 +298,10 @@ useCalledExpression(ExprSyntax CalledExpression) { } FunctionCallExprSyntaxBuilder & -FunctionCallExprSyntaxBuilder::useRightParen(RC RightParen) { +FunctionCallExprSyntaxBuilder::useRightParen(TokenSyntax RightParen) { syntax_assert_token_is(RightParen, tok::r_paren, ")"); CallLayout[cursorIndex(FunctionCallExprSyntax::Cursor::RightParen)] - = RightParen; + = RightParen.getRaw(); return *this; } @@ -474,6 +311,6 @@ FunctionCallExprSyntax FunctionCallExprSyntaxBuilder::build() const { auto RawCall = RawSyntax::make(SyntaxKind::FunctionCallExpr, CallLayout, SourcePresence::Present) ->replaceChild(FunctionCallExprSyntax::Cursor::ArgumentList, RawArgs); - auto Data = FunctionCallExprSyntaxData::make(RawCall); + auto Data = SyntaxData::make(RawCall); return { Data, Data.get() }; } diff --git a/lib/Syntax/Format.cpp b/lib/Syntax/Format.cpp index 1da34c7c1a8..7eca87f8b1d 100644 --- a/lib/Syntax/Format.cpp +++ b/lib/Syntax/Format.cpp @@ -28,15 +28,15 @@ Syntax syntax::format(Syntax Tree) { case SyntaxKind::StructDecl: { auto Struct = Tree.castTo(); auto LeftBrace = Struct.getLeftBraceToken(); - if (!LeftBrace->LeadingTrivia.contains(TriviaKind::Newline)) { - auto NewLeading = Trivia::newlines(1) + LeftBrace->LeadingTrivia; + if (!LeftBrace.getLeadingTrivia().contains(TriviaKind::Newline)) { + auto NewLeading = Trivia::newlines(1) + LeftBrace.getLeadingTrivia(); const auto NewMembers = format(Struct.getMembers()).castTo(); - LeftBrace = LeftBrace->withLeadingTrivia(NewLeading); + auto NewLeftBrace = LeftBrace.withLeadingTrivia(NewLeading); - return Struct.withMembers(NewMembers).withLeftBrace(LeftBrace); + return Struct.withMembers(NewMembers).withLeftBrace(NewLeftBrace); } break; } diff --git a/lib/Syntax/GenericSyntax.cpp b/lib/Syntax/GenericSyntax.cpp index d813d285c94..33e4df894de 100644 --- a/lib/Syntax/GenericSyntax.cpp +++ b/lib/Syntax/GenericSyntax.cpp @@ -23,192 +23,107 @@ using namespace swift::syntax; #pragma mark - conformance-requirement Data -ConformanceRequirementSyntaxData:: -ConformanceRequirementSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : GenericRequirementSyntaxData(Raw, Parent, IndexInParent) { +void ConformanceRequirementSyntax::validate() const { + auto Raw = Data->Raw; assert(Raw->Kind == SyntaxKind::ConformanceRequirement); - syntax_assert_child_kind(Raw, - ConformanceRequirementSyntax::Cursor::LeftTypeIdentifier, + syntax_assert_child_kind(Raw, Cursor::LeftTypeIdentifier, SyntaxKind::TypeIdentifier); - syntax_assert_child_token_text(Raw, - ConformanceRequirementSyntax::Cursor::Colon, + syntax_assert_child_token_text(Raw, Cursor::Colon, tok::colon, ":"); - syntax_assert_child_kind(Raw, - ConformanceRequirementSyntax::Cursor::RightTypeIdentifier, + syntax_assert_child_kind(Raw, Cursor::RightTypeIdentifier, SyntaxKind::TypeIdentifier); } -RC -ConformanceRequirementSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new ConformanceRequirementSyntaxData { - Raw, Parent, IndexInParent - } - }; -} - -RC -ConformanceRequirementSyntaxData::makeBlank() { +ConformanceRequirementSyntax +ConformanceRequirementSyntax::makeBlank() { auto Raw = RawSyntax::make(SyntaxKind::ConformanceRequirement, { RawSyntax::missing(SyntaxKind::TypeIdentifier), - TokenSyntax::missingToken(tok::colon, ":"), + RawTokenSyntax::missingToken(tok::colon, ":"), RawSyntax::missing(SyntaxKind::TypeIdentifier), }, SourcePresence::Present); - return make(Raw); -} - - -#pragma mark - generic-parameter Data - -GenericParameterSyntaxData:: -GenericParameterSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : SyntaxData(Raw, Parent, IndexInParent) { - assert(Raw->Kind == SyntaxKind::GenericParameter); -} - -RC -GenericParameterSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new GenericParameterSyntaxData { Raw, Parent, IndexInParent } - }; -} - -RC GenericParameterSyntaxData::makeBlank() { - return make(RawSyntax::make(SyntaxKind::GenericParameter, - { - TokenSyntax::missingToken(tok::identifier, ""), - TokenSyntax::missingToken(tok::colon, ":"), - RawSyntax::missing(SyntaxKind::MissingType), - }, - SourcePresence::Present)); + return make(Raw); } #pragma mark - generic-parameter API -GenericParameterSyntax:: -GenericParameterSyntax(RC Root, - const GenericParameterSyntaxData *Data) - : Syntax(Root, Data) {} - -#pragma mark - generic-parameter-list Data - -GenericParameterListSyntaxData:: -GenericParameterListSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : SyntaxData(Raw, Parent, IndexInParent) { - assert(Raw->Kind == SyntaxKind::GenericParameterList); +void GenericParameterSyntax::validate() const { + assert(Data->Raw->Kind == SyntaxKind::GenericParameter); } -RC -GenericParameterListSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new GenericParameterListSyntaxData { - Raw, Parent, IndexInParent - } - }; -} - -RC GenericParameterListSyntaxData::makeBlank() { - auto Raw = RawSyntax::make(SyntaxKind::GenericParameterList, - {}, SourcePresence::Present); - return make(Raw); +GenericParameterSyntax GenericParameterSyntax::makeBlank() { + auto Raw = RawSyntax::make(SyntaxKind::GenericParameter, + { + RawTokenSyntax::missingToken(tok::identifier, ""), + RawTokenSyntax::missingToken(tok::colon, ":"), + RawSyntax::missing(SyntaxKind::MissingType), + }, + SourcePresence::Present); + return make(Raw); } #pragma mark - -#pragma mark generic-parameter-clause Data +#pragma mark - generic-parameter-clause API -GenericParameterClauseSyntaxData:: -GenericParameterClauseSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : SyntaxData(Raw, Parent, IndexInParent) { - syntax_assert_child_token_text(Raw, - GenericParameterClauseSyntax::Cursor::LeftAngleBracketToken, +void GenericParameterClauseSyntax::validate() const { + auto Raw = Data->Raw; + syntax_assert_child_token_text(Raw, Cursor::LeftAngleBracketToken, tok::l_angle, "<"); - syntax_assert_child_kind(Raw, - GenericParameterClauseSyntax::Cursor::GenericParameterList, + syntax_assert_child_kind(Raw, Cursor::GenericParameterList, SyntaxKind::GenericParameterList); - syntax_assert_child_token_text(Raw, - GenericParameterClauseSyntax::Cursor::RightAngleBracketToken, + syntax_assert_child_token_text(Raw, Cursor::RightAngleBracketToken, tok::r_angle, ">"); } -RC -GenericParameterClauseSyntaxData::make(const RC Raw, - const SyntaxData *Parent, - const CursorIndex IndexInParent) { - return RC { - new GenericParameterClauseSyntaxData { - Raw, Parent, IndexInParent, - } - }; +GenericParameterClauseSyntax +GenericParameterClauseSyntax::makeBlank() { + auto Raw = RawSyntax::make( + SyntaxKind::GenericParameterClause, + { + RawTokenSyntax::missingToken(tok::l_angle, "<"), + RawSyntax::missing(SyntaxKind::GenericParameterList), + RawTokenSyntax::missingToken(tok::r_angle, ">"), + }, + SourcePresence::Present); + return make(Raw); } -RC -GenericParameterClauseSyntaxData::makeBlank() { - return make(RawSyntax::make(SyntaxKind::GenericParameterClause, - { - TokenSyntax::missingToken(tok::l_angle, "<"), - RawSyntax::missing(SyntaxKind::GenericParameterList), - TokenSyntax::missingToken(tok::r_angle, ">"), - }, - SourcePresence::Present)); -} - -#pragma mark - generic-parameter-clause API - -GenericParameterClauseSyntax:: -GenericParameterClauseSyntax(const RC Root, - const GenericParameterClauseSyntaxData *Data) - : Syntax(Root, Data) {} - #pragma mark - generic-parameter-clause Builder GenericParameterClauseBuilder::GenericParameterClauseBuilder() - : LeftAngleToken(TokenSyntax::missingToken(tok::l_angle, "<")), + : LeftAngleToken(RawTokenSyntax::missingToken(tok::l_angle, "<")), ParameterListLayout(RawSyntax::missing(SyntaxKind::GenericParameterList) ->Layout), - RightAngleToken(TokenSyntax::missingToken(tok::r_angle, ">")) {} + RightAngleToken(RawTokenSyntax::missingToken(tok::r_angle, ">")) {} GenericParameterClauseBuilder &GenericParameterClauseBuilder:: -useLeftAngleBracket(RC LeftAngle) { +useLeftAngleBracket(TokenSyntax LeftAngle) { syntax_assert_token_is(LeftAngle, tok::l_angle, "<"); - LeftAngleToken = LeftAngle; + LeftAngleToken = LeftAngle.getRawToken(); return *this; } GenericParameterClauseBuilder &GenericParameterClauseBuilder:: -addParameter(llvm::Optional> MaybeComma, +addParameter(llvm::Optional MaybeComma, GenericParameterSyntax Parameter) { if (MaybeComma.hasValue()) { syntax_assert_token_is(MaybeComma.getValue(), tok::comma, ","); - ParameterListLayout.push_back(MaybeComma.getValue()); + ParameterListLayout.push_back(MaybeComma->getRaw()); } else { - ParameterListLayout.push_back(TokenSyntax::missingToken(tok::comma, ",")); + ParameterListLayout.push_back( + RawTokenSyntax::missingToken(tok::comma, ",")); } ParameterListLayout.push_back(Parameter.getRaw()); return *this; } GenericParameterClauseBuilder &GenericParameterClauseBuilder:: -useRightAngleBracket(RC RightAngle) { +useRightAngleBracket(TokenSyntax RightAngle) { syntax_assert_token_is(RightAngle, tok::r_angle, ">"); - RightAngleToken = RightAngle; + RightAngleToken = RightAngle.getRawToken(); return *this; } @@ -222,16 +137,14 @@ GenericParameterClauseSyntax GenericParameterClauseBuilder::build() const { RightAngleToken, }, SourcePresence::Present); - auto Data = GenericParameterClauseSyntaxData::make(Raw); + auto Data = SyntaxData::make(Raw); return { Data, Data.get() }; } -#pragma mark - generic-where-clause Data +#pragma mark - generic-where-clause API -GenericWhereClauseSyntaxData:: -GenericWhereClauseSyntaxData(const RC Raw, const SyntaxData *Parent, - const CursorIndex IndexInParent) - : SyntaxData(Raw, Parent, IndexInParent) { +void GenericWhereClauseSyntax::validate() const { + auto Raw = Data->Raw; assert(Raw->Kind == SyntaxKind::GenericWhereClause); syntax_assert_child_token_text(Raw, GenericWhereClauseSyntax::Cursor::WhereKeyword, tok::kw_where, "where"); @@ -240,35 +153,21 @@ GenericWhereClauseSyntaxData(const RC Raw, const SyntaxData *Parent, SyntaxKind::GenericRequirementList); } -RC -GenericWhereClauseSyntaxData::make(const RC Raw, - const SyntaxData *Parent, - const CursorIndex IndexInParent) { - return RC { - new GenericWhereClauseSyntaxData { Raw, Parent, IndexInParent } - }; +GenericWhereClauseSyntax GenericWhereClauseSyntax::makeBlank() { + auto Raw = RawSyntax::make( + SyntaxKind::GenericWhereClause, + { + RawTokenSyntax::missingToken(tok::kw_where, "where"), + RawSyntax::missing(SyntaxKind::GenericRequirementList), + }, + SourcePresence::Present); + return make(Raw); } -RC GenericWhereClauseSyntaxData::makeBlank() { - return make(RawSyntax::make(SyntaxKind::GenericWhereClause, - { - TokenSyntax::missingToken(tok::kw_where, "where"), - RawSyntax::missing(SyntaxKind::GenericRequirementList), - }, - SourcePresence::Present)); -} - -#pragma mark - generic-where-clause API - -GenericWhereClauseSyntax:: -GenericWhereClauseSyntax(RC Root, - const GenericWhereClauseSyntaxData *Data) - : Syntax(Root, Data) {} - GenericWhereClauseSyntax GenericWhereClauseSyntax:: -withWhereKeyword(RC NewWhereKeyword) const { +withWhereKeyword(TokenSyntax NewWhereKeyword) const { syntax_assert_token_is(NewWhereKeyword, tok::kw_where, "where"); - return Data->replaceChild(NewWhereKeyword, + return Data->replaceChild(NewWhereKeyword.getRaw(), Cursor::WhereKeyword); } @@ -278,130 +177,59 @@ withRequirementList(GenericRequirementListSyntax NewRequirements) const { Cursor::RequirementList); } -#pragma mark - same-type-requirement Data - -SameTypeRequirementSyntaxData:: -SameTypeRequirementSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : GenericRequirementSyntaxData(Raw, Parent, IndexInParent) { - assert(Raw->Kind == SyntaxKind::SameTypeRequirement); - assert(Raw->Layout.size() == 3); - syntax_assert_child_kind(Raw, - SameTypeRequirementSyntax::Cursor::LeftTypeIdentifier, - SyntaxKind::TypeIdentifier); - syntax_assert_child_token_text(Raw, - SameTypeRequirementSyntax::Cursor::EqualityToken, - tok::oper_binary_spaced, "=="); - assert(Raw->getChild(SameTypeRequirementSyntax::Cursor::RightType)->isType()); -} - -RC -SameTypeRequirementSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new SameTypeRequirementSyntaxData { - Raw, Parent, IndexInParent - } - }; -} - -RC SameTypeRequirementSyntaxData::makeBlank() { - return make(RawSyntax::make(SyntaxKind::SameTypeRequirement, - { - RawSyntax::missing(SyntaxKind::TypeIdentifier), - TokenSyntax::missingToken(tok::equal, "="), - RawSyntax::missing(SyntaxKind::MissingType), - }, - SourcePresence::Present)); -} - #pragma mark - same-type-requirement API -SameTypeRequirementSyntax:: -SameTypeRequirementSyntax(RC Root, - const SameTypeRequirementSyntaxData *Data) - : Syntax(Root, Data) {} - -#pragma mark - generic-argument-list Data - -GenericArgumentListSyntaxData:: -GenericArgumentListSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : SyntaxData(Raw, Parent, IndexInParent) { - assert(Raw->Kind == SyntaxKind::GenericArgumentList); +void SameTypeRequirementSyntax::validate() const { + auto Raw = Data->Raw; + assert(Raw->Kind == SyntaxKind::SameTypeRequirement); + assert(Raw->Layout.size() == 3); + syntax_assert_child_kind(Raw, Cursor::LeftTypeIdentifier, + SyntaxKind::TypeIdentifier); + syntax_assert_child_token_text(Raw, Cursor::EqualityToken, + tok::oper_binary_spaced, "=="); + assert(Raw->getChild(Cursor::RightType)->isType()); } -RC -GenericArgumentListSyntaxData::make(RC Raw, const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new GenericArgumentListSyntaxData { - Raw, Parent, IndexInParent - } - }; -} - -RC GenericArgumentListSyntaxData::makeBlank() { - auto Raw = RawSyntax::make(SyntaxKind::GenericArgumentList, {}, - SourcePresence::Present); - return make(Raw); -} - - -#pragma mark - generic-argument-list API (TODO) - -#pragma mark - generic-argument-clause Data - -GenericArgumentClauseSyntaxData:: -GenericArgumentClauseSyntaxData(RC Raw, const SyntaxData *Parent, - CursorIndex IndexInParent) - : SyntaxData(Raw, Parent, IndexInParent) {} - -RC -GenericArgumentClauseSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new GenericArgumentClauseSyntaxData { Raw, Parent, IndexInParent } - }; -} - -RC -GenericArgumentClauseSyntaxData::makeBlank() { - auto Raw = RawSyntax::make(SyntaxKind::GenericArgumentClause, +SameTypeRequirementSyntax SameTypeRequirementSyntax::makeBlank() { + auto Raw = RawSyntax::make(SyntaxKind::SameTypeRequirement, { - TokenSyntax::missingToken(tok::l_angle, "<"), - RawSyntax::missing(SyntaxKind::GenericArgumentList), - TokenSyntax::missingToken(tok::r_angle, ">"), + RawSyntax::missing(SyntaxKind::TypeIdentifier), + RawTokenSyntax::missingToken(tok::equal, "="), + RawSyntax::missing(SyntaxKind::MissingType), }, SourcePresence::Present); - return make(Raw); + return make(Raw); } -#pragma mark - generic-argument-clause API +#pragma mark - generic-argument-clause API (TODO) + +GenericArgumentClauseSyntax +GenericArgumentClauseSyntax::makeBlank() { + auto Raw = RawSyntax::make(SyntaxKind::GenericArgumentClause, + { + RawTokenSyntax::missingToken(tok::l_angle, "<"), + RawSyntax::missing(SyntaxKind::GenericArgumentList), + RawTokenSyntax::missingToken(tok::r_angle, ">"), + }, + SourcePresence::Present); + return make(Raw); +} -GenericArgumentClauseSyntax:: -GenericArgumentClauseSyntax(RC Root, - const GenericArgumentClauseSyntaxData *Data) - : Syntax(Root, Data) {} GenericArgumentClauseSyntax GenericArgumentClauseSyntax:: -withLeftAngleBracket(RC NewLeftAngleBracket) const { +withLeftAngleBracket(TokenSyntax NewLeftAngleBracket) const { syntax_assert_token_is(NewLeftAngleBracket, tok::l_angle, "<"); return Data->replaceChild( - NewLeftAngleBracket, Cursor::LeftAngleBracketToken); + NewLeftAngleBracket.getRaw(), Cursor::LeftAngleBracketToken); } GenericArgumentClauseSyntax GenericArgumentClauseSyntax:: -withRightAngleBracket(RC NewRightAngleBracket) const { +withRightAngleBracket(TokenSyntax NewRightAngleBracket) const { syntax_assert_token_is(NewRightAngleBracket, tok::r_angle, ">"); return Data->replaceChild( - NewRightAngleBracket, Cursor::RightAngleBracketToken); + NewRightAngleBracket.getRaw(), Cursor::RightAngleBracketToken); } #pragma mark - generic-argument-clause Builder @@ -411,29 +239,30 @@ GenericArgumentClauseBuilder::GenericArgumentClauseBuilder() SyntaxFactory::makeBlankGenericArgumentClause().getRaw()->Layout) {} GenericArgumentClauseBuilder &GenericArgumentClauseBuilder:: -useLeftAngleBracket(RC LeftAngle) { +useLeftAngleBracket(TokenSyntax LeftAngle) { syntax_assert_token_is(LeftAngle, tok::l_angle, "<"); - LeftAngleToken = LeftAngle; + LeftAngleToken = LeftAngle.getRawToken(); return *this; } GenericArgumentClauseBuilder &GenericArgumentClauseBuilder:: -addGenericArgument(llvm::Optional> MaybeComma, +addGenericArgument(llvm::Optional MaybeComma, TypeSyntax ArgumentTypeSyntax) { if (MaybeComma.hasValue()) { syntax_assert_token_is(MaybeComma.getValue(), tok::comma, ","); - ArgumentListLayout.push_back(MaybeComma.getValue()); + ArgumentListLayout.push_back(MaybeComma->getRaw()); } else { - ArgumentListLayout.push_back(TokenSyntax::missingToken(tok::comma, ",")); + ArgumentListLayout.push_back( + RawTokenSyntax::missingToken(tok::comma, ",")); } ArgumentListLayout.push_back(ArgumentTypeSyntax.getRaw()); return *this; } GenericArgumentClauseBuilder &GenericArgumentClauseBuilder:: -useRightAngleBracket(RC RightAngle) { +useRightAngleBracket(TokenSyntax RightAngle) { syntax_assert_token_is(RightAngle, tok::r_angle, ">"); - RightAngleToken = RightAngle; + RightAngleToken = RightAngle.getRawToken(); return *this; } @@ -449,6 +278,6 @@ GenericArgumentClauseSyntax GenericArgumentClauseBuilder::build() const { RightAngleToken }, SourcePresence::Present); - auto Data = GenericArgumentClauseSyntaxData::make(Raw); + auto Data = SyntaxData::make(Raw); return { Data, Data.get() }; } diff --git a/lib/Syntax/LegacyASTTransformer.cpp b/lib/Syntax/LegacyASTTransformer.cpp index f0e933e5003..3852eaff327 100644 --- a/lib/Syntax/LegacyASTTransformer.cpp +++ b/lib/Syntax/LegacyASTTransformer.cpp @@ -26,16 +26,17 @@ using namespace swift::syntax; namespace { bool tokenContainsOffset(unsigned Offset, - const std::pair, - AbsolutePosition> &TokAndPos) { + const std::pair, + AbsolutePosition> &TokAndPos) { auto Start = TokAndPos.second.getOffset(); auto End = Start + TokAndPos.first->getText().size(); return Offset >= Start && Offset < End; } - std::vector> - getTokenSyntaxsInRange(SourceRange Range, SourceManager &SourceMgr, - unsigned BufferID, - const TokenPositionList &Tokens) { + + std::vector> + getRawTokenSyntaxesInRange(SourceRange Range, SourceManager &SourceMgr, + unsigned BufferID, + const TokenPositionList &Tokens) { auto StartOffset = SourceMgr.getLocOffsetInBuffer(Range.Start, BufferID); auto EndOffset = SourceMgr.getLocOffsetInBuffer(Range.End, BufferID); @@ -60,7 +61,7 @@ namespace { assert(End.base() != Tokens.end()); assert(Start <= End.base()); - std::vector> TokensInRange; + std::vector> TokensInRange; while (Start < End.base()) { TokensInRange.push_back(Start->first); @@ -141,7 +142,7 @@ SourceLoc LegacyASTTransformer::getEndLocForExpr(const Expr *E) const { } RC LegacyASTTransformer::getUnknownSyntax(SourceRange SR) { - auto ComprisingTokens = getTokenSyntaxsInRange(SR, SourceMgr, + auto ComprisingTokens = getRawTokenSyntaxesInRange(SR, SourceMgr, BufferID, Tokens); RawSyntax::LayoutList Layout; std::copy(ComprisingTokens.begin(), @@ -150,40 +151,40 @@ RC LegacyASTTransformer::getUnknownSyntax(SourceRange SR) { auto Raw = RawSyntax::make(SyntaxKind::Unknown, Layout, SourcePresence::Present); - return UnknownSyntaxData::make(Raw); + return SyntaxData::make(Raw); } RC LegacyASTTransformer::getUnknownDecl(Decl *D) { SourceRange SR {getStartLocForDecl(D),getEndLocForDecl(D)}; - auto ComprisingTokens = getTokenSyntaxsInRange(SR, SourceMgr, + auto ComprisingTokens = getRawTokenSyntaxesInRange(SR, SourceMgr, BufferID, Tokens); RawSyntax::LayoutList Layout; std::copy(ComprisingTokens.begin(), ComprisingTokens.end(), std::back_inserter(Layout)); - auto Raw = RawSyntax::make(SyntaxKind::UnknownExpr, + auto Raw = RawSyntax::make(SyntaxKind::UnknownDecl, Layout, SourcePresence::Present); - return UnknownDeclSyntaxData::make(Raw); + return SyntaxData::make(Raw); } RC LegacyASTTransformer::getUnknownStmt(Stmt *S) { SourceRange SR { S->getStartLoc(), getEndLocForStmt(S) }; - auto ComprisingTokens = getTokenSyntaxsInRange(SR, SourceMgr, + auto ComprisingTokens = getRawTokenSyntaxesInRange(SR, SourceMgr, BufferID, Tokens); RawSyntax::LayoutList Layout; std::copy(ComprisingTokens.begin(), ComprisingTokens.end(), std::back_inserter(Layout)); - auto Raw = RawSyntax::make(SyntaxKind::UnknownExpr, + auto Raw = RawSyntax::make(SyntaxKind::UnknownStmt, Layout, SourcePresence::Present); - return UnknownStmtSyntaxData::make(Raw); + return SyntaxData::make(Raw); } RC LegacyASTTransformer::getUnknownExpr(Expr *E) { SourceRange SR { E->getStartLoc(), getEndLocForExpr(E) }; - auto ComprisingTokens = getTokenSyntaxsInRange(SR, SourceMgr, + auto ComprisingTokens = getRawTokenSyntaxesInRange(SR, SourceMgr, BufferID, Tokens); RawSyntax::LayoutList Layout; std::copy(ComprisingTokens.begin(), @@ -192,7 +193,7 @@ RC LegacyASTTransformer::getUnknownExpr(Expr *E) { auto Raw = RawSyntax::make(SyntaxKind::UnknownExpr, Layout, SourcePresence::Present); - return UnknownExprSyntaxData::make(Raw); + return SyntaxData::make(Raw); } #pragma mark - Declarations @@ -598,13 +599,6 @@ LegacyASTTransformer::visitFallthroughStmt(FallthroughStmt *S, return SyntaxFactory::makeFallthroughStmt(FallthroughToken).Root; } -RC -LegacyASTTransformer::visitIfConfigStmt(IfConfigStmt *S, - const SyntaxData *Parent, - const CursorIndex IndexInParent) { - return getUnknownStmt(S); -} - RC LegacyASTTransformer::visitFailStmt(FailStmt *S, const SyntaxData *Parent, @@ -1303,7 +1297,7 @@ LegacyASTTransformer::visitKeyPathDotExpr(KeyPathDotExpr *E, return getUnknownExpr(E); } -RC +TokenSyntax syntax::findTokenSyntax(tok ExpectedKind, OwnedString ExpectedText, SourceManager &SourceMgr, @@ -1326,7 +1320,7 @@ syntax::findTokenSyntax(tok ExpectedKind, if (Offset == TokStart) { if (Tok->getTokenKind() == ExpectedKind && (ExpectedText.empty() || Tok->getText() == ExpectedText.str())) { - return Tok; + return make(Tok); } else { return TokenSyntax::missingToken(ExpectedKind, ExpectedText); } diff --git a/lib/Syntax/README.md b/lib/Syntax/README.md index 03440afa92e..8dd6eb2f559 100644 --- a/lib/Syntax/README.md +++ b/lib/Syntax/README.md @@ -236,7 +236,7 @@ tokens, represented by the `TokenSyntax` class. - `RawSyntax` store no parental relationships and can therefore be shared among syntax nodes if they have identical content. -### TokenSyntax +### RawTokenSyntax These are special cases of `RawSyntax` and represent all terminals in the grammar. Aside from the token kind and the text, they have two very important @@ -245,12 +245,12 @@ pieces of information for full-fidelity source: leading and trailing source #### TokenSyntax summary -- `TokenSyntax` are `RawSyntax` and represent the terminals in the Swift +- `RawTokenSyntax` are `RawSyntax` and represent the terminals in the Swift grammar. -- Like `RawSyntax`, `TokenSyntax` are immutable. -- `TokenSyntax` do not have pointer equality, as they can be shared among syntax +- Like `RawSyntax`, `RawTokenSyntax` are immutable. +- `RawTokenSyntax` do have pointer equality, but they can be shared among syntax nodes. -- `TokenSyntax` have *leading-* and *trailing trivia*, the purely syntactic +- `RawTokenSyntax` have *leading-* and *trailing trivia*, the purely syntactic formatting information like whitespace and comments. ### Trivia @@ -370,10 +370,10 @@ A couple of remarks about the `EOF` token: additional information: a pointer to a parent, the position in which the node occurs in its parent, and cached children. -For example, if we have a `StructDeclSyntaxData`, wrapping a `RawSyntax` for a +For example, if we have a `SyntaxData`, wrapping a `RawSyntax` for a struct declaration, we might ask for the generic parameter clause. At first, this is only represented in the raw syntax. On first ask, we thaw those out by -creating a new `GenericParameterClauseSyntaxData`, cache it as our child, set +creating a new `SyntaxData`, cache it as our child, set its parent to `this`, and send it back to the caller. These cached children are strong references, keeping the syntax tree alive in memory. @@ -447,7 +447,7 @@ auto Block = SyntaxFactory::makeBlankCodeBlockStmt() // Returns a new ReturnStmtSyntax with the root set to the Block // above, and the parent set to the StmtListSyntax. -auto MyReturn = Block.getStatement(0).castTo; +auto MyReturn = Block.getStatement(0).castTo(); ``` Here's what the corresponding object diagram would look like starting with @@ -456,7 +456,7 @@ Here's what the corresponding object diagram would look like starting with ![Syntax Example](.doc/SyntaxExample.png) Legend: -- Green: `RawSyntax` types (`TokenSyntax` is a `RawSyntax`) +- Green: `RawSyntax` types (`RawTokenSyntax` is a `RawSyntax`) - Red: `SyntaxData` types - Blue: `Syntax` types - Gray: `Trivia` @@ -484,8 +484,6 @@ Here's a handy checklist when implementing a production in the grammar. are affected. - **Add the `Syntax` bug label!** - Add a *kind* to include/swift/Syntax/SyntaxKinds.def -- Create the `${KIND}SyntaxData` class. - - Cached children members as `RC<${CHILDKIND}SyntaxData>` - Create the `${KIND}Syntax` class. Be sure to implement the following: - Define the `Cursor` enum for the syntax node. This specifies all of the @@ -494,7 +492,7 @@ Here's a handy checklist when implementing a production in the grammar. `same-type-requirement -> type-identifier '==' type` That's three terms in the production, and you can see this reflected in the - `StructDeclSyntaxData` class: + `SameTypeRequirementSyntax` class: ```c++ enum Cursor : CursorIndex { @@ -509,7 +507,6 @@ Here's a handy checklist when implementing a production in the grammar. what you changed. `print` the new node and check the text. - Check that the new node has a different parent. - Getters for all layout elements (e.g. `getLeftTypeIdentifier()`) - - Caching mechanics in corresponding `${KIND}SyntaxData` class. - Add a C++ unit test. - After `get`ing the child, verify: - The child's parent and root are correct diff --git a/lib/Syntax/RawSyntax.cpp b/lib/Syntax/RawSyntax.cpp index e68c027dfa3..9c873838ff3 100644 --- a/lib/Syntax/RawSyntax.cpp +++ b/lib/Syntax/RawSyntax.cpp @@ -36,7 +36,7 @@ void dumpSyntaxKind(llvm::raw_ostream &OS, const SyntaxKind Kind) { } // end anonymous namespace void RawSyntax::print(llvm::raw_ostream &OS) const { - if (const auto Tok = dyn_cast(this)) { + if (const auto Tok = dyn_cast(this)) { Tok->print(OS); } @@ -71,7 +71,7 @@ void RawSyntax::dump(llvm::raw_ostream &OS, unsigned Indent) const { } switch ((*LE)->Kind) { case SyntaxKind::Token: - llvm::cast(*LE)->dump(OS, Indent + 1); + llvm::cast(*LE)->dump(OS, Indent + 1); break; default: (*LE)->dump(OS, Indent + 1); @@ -87,7 +87,7 @@ bool RawSyntax::accumulateAbsolutePosition( for (auto LE : Layout) { switch (LE->Kind) { case SyntaxKind::Token: { - auto Tok = llvm::cast(LE); + auto Tok = llvm::cast(LE); for (auto Leader : Tok->LeadingTrivia) { Leader.accumulateAbsolutePosition(Pos); } diff --git a/lib/Syntax/TokenSyntax.cpp b/lib/Syntax/RawTokenSyntax.cpp similarity index 84% rename from lib/Syntax/TokenSyntax.cpp rename to lib/Syntax/RawTokenSyntax.cpp index 2212236a525..54b4b574926 100644 --- a/lib/Syntax/TokenSyntax.cpp +++ b/lib/Syntax/RawTokenSyntax.cpp @@ -1,4 +1,4 @@ -//===--- TokenSyntax.cpp - Swift Token Syntax Implementation --------------===// +//===--- RawTokenSyntax.cpp - Swift Token Syntax Implementation -----------===// // // This source file is part of the Swift.org open source project // @@ -16,28 +16,28 @@ using namespace swift; using namespace swift::syntax; -TokenSyntax::TokenSyntax() +RawTokenSyntax::RawTokenSyntax() : RawSyntax(SyntaxKind::Token, {}, SourcePresence::Missing), TokenKind(tok::NUM_TOKENS), Text(OwnedString()), LeadingTrivia({}), TrailingTrivia({}) {} -TokenSyntax::TokenSyntax(tok TokenKind, OwnedString Text, - const SourcePresence Presence) +RawTokenSyntax::RawTokenSyntax(tok TokenKind, OwnedString Text, + const SourcePresence Presence) : RawSyntax(SyntaxKind::Token, {}, Presence), TokenKind(TokenKind), Text(Text), LeadingTrivia({}), TrailingTrivia({}) {} -TokenSyntax::TokenSyntax(tok TokenKind, OwnedString Text, - const SourcePresence Presence, - const Trivia &LeadingTrivia, - const Trivia &TrailingTrivia) +RawTokenSyntax::RawTokenSyntax(tok TokenKind, OwnedString Text, + const SourcePresence Presence, + const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia) : RawSyntax(SyntaxKind::Token, {}, Presence), TokenKind(TokenKind), Text(Text), LeadingTrivia(LeadingTrivia), TrailingTrivia(TrailingTrivia) {} AbsolutePosition -TokenSyntax::accumulateAbsolutePosition(AbsolutePosition &Pos) const { +RawTokenSyntax::accumulateAbsolutePosition(AbsolutePosition &Pos) const { for (auto Leader : LeadingTrivia) { Leader.accumulateAbsolutePosition(Pos); } @@ -53,7 +53,7 @@ TokenSyntax::accumulateAbsolutePosition(AbsolutePosition &Pos) const { return Start; } -void TokenSyntax::dumpKind(llvm::raw_ostream &OS) const { +void RawTokenSyntax::dumpKind(llvm::raw_ostream &OS) const { switch (getTokenKind()) { case tok::unknown: OS << "unknown"; @@ -116,7 +116,7 @@ void TokenSyntax::dumpKind(llvm::raw_ostream &OS) const { } } -void TokenSyntax::dump(llvm::raw_ostream &OS, unsigned Indent) const { +void RawTokenSyntax::dump(llvm::raw_ostream &OS, unsigned Indent) const { auto indent = [&](unsigned Amount) { for (decltype(Amount) i = 0; i < Amount; ++i) { OS << ' '; diff --git a/lib/Syntax/StmtSyntax.cpp b/lib/Syntax/StmtSyntax.cpp index 15890b157ce..0cfc35f248e 100644 --- a/lib/Syntax/StmtSyntax.cpp +++ b/lib/Syntax/StmtSyntax.cpp @@ -17,355 +17,181 @@ using namespace swift; using namespace swift::syntax; -#pragma mark - statement API - -StmtSyntax::StmtSyntax(const RC Root, const StmtSyntaxData *Data) - : Syntax(Root, Data) {} - -#pragma mark - unknown-statement Data - -UnknownStmtSyntaxData::UnknownStmtSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : UnknownSyntaxData(Raw, Parent, IndexInParent) { - assert(Raw->Kind == SyntaxKind::UnknownStmt); -} - -RC -UnknownStmtSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - auto UnknownRaw = RawSyntax::make(SyntaxKind::UnknownStmt, Raw->Layout, - Raw->Presence); - return RC { - new UnknownStmtSyntaxData { - UnknownRaw, Parent, IndexInParent - } - }; -} - #pragma mark - unknown-statement API -UnknownStmtSyntax::UnknownStmtSyntax(const RC Root, - const UnknownStmtSyntaxData *Data) - : UnknownSyntax(Root, Data) {} - -#pragma mark fallthrough-statement Data - -FallthroughStmtSyntaxData::FallthroughStmtSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : StmtSyntaxData(Raw, Parent, IndexInParent) { - assert(Raw->Kind == SyntaxKind::FallthroughStmt); - assert(Raw->Layout.size() == 1); - syntax_assert_child_token_text(Raw, - FallthroughStmtSyntax::Cursor::FallthroughKeyword, - tok::kw_fallthrough, "fallthrough"); -} - -RC -FallthroughStmtSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new FallthroughStmtSyntaxData { Raw, Parent, IndexInParent } - }; -} - -RC FallthroughStmtSyntaxData::makeBlank() { - return make(RawSyntax::make(SyntaxKind::FallthroughStmt, - { - TokenSyntax::missingToken(tok::kw_fallthrough, "fallthrough"), - }, - SourcePresence::Present)); +void UnknownStmtSyntax::validate() const { + assert(Data->Raw->Kind == SyntaxKind::UnknownStmt); } #pragma mark fallthrough-statement API -FallthroughStmtSyntax:: -FallthroughStmtSyntax(const RC Root, - const FallthroughStmtSyntaxData *Data) - : StmtSyntax(Root, Data) {} - -FallthroughStmtSyntax -FallthroughStmtSyntax::make(RC Raw, const SyntaxData *Parent, - CursorIndex IndexInParent) { - assert(Raw->Layout.size() == 1); - syntax_assert_child_token_text(Raw, - Cursor::FallthroughKeyword, - tok::kw_fallthrough, "fallthrough"); - auto Data = FallthroughStmtSyntaxData::make(Raw, Parent, IndexInParent); - return FallthroughStmtSyntax { - Data, Data.get(), - }; +FallthroughStmtSyntax FallthroughStmtSyntax::makeBlank() { + return make( + RawSyntax::make(SyntaxKind::FallthroughStmt, + { + RawTokenSyntax::missingToken(tok::kw_fallthrough, "fallthrough"), + }, + SourcePresence::Present)); } -RC FallthroughStmtSyntax::getFallthroughKeyword() const { - return cast(getRaw()->getChild(Cursor::FallthroughKeyword)); +void FallthroughStmtSyntax::validate() const { + assert(Data->Raw->Kind == SyntaxKind::FallthroughStmt); + assert(Data->Raw->Layout.size() == 1); + syntax_assert_child_token_text(Data->Raw, Cursor::FallthroughKeyword, + tok::kw_fallthrough, "fallthrough"); +} + +TokenSyntax FallthroughStmtSyntax::getFallthroughKeyword() const { + return { Root, Data->getChild(Cursor::FallthroughKeyword).get() }; } FallthroughStmtSyntax FallthroughStmtSyntax:: -withFallthroughKeyword(RC NewFallthroughKeyword) const { +withFallthroughKeyword(TokenSyntax NewFallthroughKeyword) const { syntax_assert_token_is(NewFallthroughKeyword, tok::kw_fallthrough, "fallthrough"); - return Data->replaceChild(NewFallthroughKeyword, - Cursor::FallthroughKeyword); + return Data->replaceChild( + NewFallthroughKeyword.getRaw(), Cursor::FallthroughKeyword); } +#pragma mark code-block API -CodeBlockStmtSyntaxData::CodeBlockStmtSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : StmtSyntaxData(Raw, Parent, IndexInParent) { - assert(Raw->Kind == SyntaxKind::CodeBlockStmt); - syntax_assert_child_token_text(Raw, CodeBlockStmtSyntax::Cursor::LeftBrace, - tok::l_brace, "{"); - syntax_assert_child_kind(Raw, CodeBlockStmtSyntax::Cursor::Elements, - SyntaxKind::StmtList); - syntax_assert_child_token_text(Raw, CodeBlockStmtSyntax::Cursor::RightBrace, - tok::r_brace, "}"); -} - -RC -CodeBlockStmtSyntaxData::make(RC Raw, const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new CodeBlockStmtSyntaxData { Raw, Parent, IndexInParent } - }; -} - -RC -CodeBlockStmtSyntaxData::makeBlank() { - return make(RawSyntax::make(SyntaxKind::CodeBlockStmt, +CodeBlockStmtSyntax +CodeBlockStmtSyntax::makeBlank() { + return make(RawSyntax::make(SyntaxKind::CodeBlockStmt, { - TokenSyntax::missingToken(tok::l_brace, "{"), + RawTokenSyntax::missingToken(tok::l_brace, "{"), RawSyntax::missing(SyntaxKind::StmtList), - TokenSyntax::missingToken(tok::r_brace, "}"), + RawTokenSyntax::missingToken(tok::r_brace, "}"), }, SourcePresence::Present)); } -#pragma mark - break-statement Data - -BreakStmtSyntaxData::BreakStmtSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : StmtSyntaxData(Raw, Parent, IndexInParent) { - assert(Raw->Layout.size() == 2); - syntax_assert_child_token_text(Raw, BreakStmtSyntax::Cursor::BreakKeyword, - tok::kw_break, "break"); - syntax_assert_child_token(Raw, BreakStmtSyntax::Cursor::Label, - tok::identifier); -} - -RC -BreakStmtSyntaxData::make(RC Raw, const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new BreakStmtSyntaxData { - Raw, Parent, IndexInParent - } - }; -} - -RC BreakStmtSyntaxData::makeBlank() { - return make(RawSyntax::make(SyntaxKind::BreakStmt, - { - TokenSyntax::missingToken(tok::kw_break, - "break"), - TokenSyntax::missingToken(tok::identifier, ""), - }, - SourcePresence::Present)); +void CodeBlockStmtSyntax::validate() const { + assert(Data->Raw->Kind == SyntaxKind::CodeBlockStmt); + syntax_assert_child_token_text(Data->Raw, Cursor::LeftBrace, + tok::l_brace, "{"); + syntax_assert_child_kind(Data->Raw, Cursor::Elements, + SyntaxKind::StmtList); + syntax_assert_child_token_text(Data->Raw, Cursor::RightBrace, + tok::r_brace, "}"); } #pragma mark - break-statement API -BreakStmtSyntax::BreakStmtSyntax(const RC Root, - BreakStmtSyntaxData *Data) - : StmtSyntax(Root, Data) {} - -BreakStmtSyntax BreakStmtSyntax::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - auto Data = BreakStmtSyntaxData::make(Raw, Parent, IndexInParent); - return { Data, Data.get() }; -} - -BreakStmtSyntax BreakStmtSyntax::makeBlank() { - auto Data = BreakStmtSyntaxData::makeBlank(); - return { Data, Data.get() }; -} - -RC BreakStmtSyntax::getBreakKeyword() const { - return cast(getRaw()->getChild(Cursor::BreakKeyword)); -} - -BreakStmtSyntax -BreakStmtSyntax::withBreakKeyword(RC NewBreakKeyword) const { - syntax_assert_token_is(NewBreakKeyword, tok::kw_break, "break"); - return Data->replaceChild(NewBreakKeyword, - Cursor::BreakKeyword); -} - -RC BreakStmtSyntax::getLabel() const { - return cast(getRaw()->getChild(Cursor::Label)); -} - -BreakStmtSyntax BreakStmtSyntax::withLabel(RC NewLabel) const { - assert(NewLabel->getTokenKind() == tok::identifier); - return Data->replaceChild(NewLabel, Cursor::Label); -} - -#pragma mark - continue-statement Data - -ContinueStmtSyntaxData::ContinueStmtSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : StmtSyntaxData(Raw, Parent, IndexInParent) { - assert(Raw->Layout.size() == 2); - syntax_assert_child_token_text(Raw, - ContinueStmtSyntax::Cursor::ContinueKeyword, - tok::kw_continue, "continue"); - syntax_assert_child_token(Raw, ContinueStmtSyntax::Cursor::Label, +void BreakStmtSyntax::validate() const { + assert(Data->Raw->Layout.size() == 2); + syntax_assert_child_token_text(Data->Raw, Cursor::BreakKeyword, + tok::kw_break, "break"); + syntax_assert_child_token(Data->Raw, BreakStmtSyntax::Cursor::Label, tok::identifier); } -RC -ContinueStmtSyntaxData::make(RC Raw, const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new ContinueStmtSyntaxData { - Raw, Parent, IndexInParent - } - }; +BreakStmtSyntax BreakStmtSyntax::makeBlank() { + return make(RawSyntax::make(SyntaxKind::BreakStmt, + { + RawTokenSyntax::missingToken(tok::kw_break, + "break"), + RawTokenSyntax::missingToken(tok::identifier, ""), + }, + SourcePresence::Present)); } -RC ContinueStmtSyntaxData::makeBlank() { - return make(RawSyntax::make(SyntaxKind::ContinueStmt, - { - TokenSyntax::missingToken(tok::kw_continue, - "continue"), - TokenSyntax::missingToken(tok::identifier, ""), - }, - SourcePresence::Present)); +TokenSyntax BreakStmtSyntax::getBreakKeyword() const { + return { Root, Data->getChild(Cursor::BreakKeyword).get() }; +} + +BreakStmtSyntax +BreakStmtSyntax::withBreakKeyword(TokenSyntax NewBreakKeyword) const { + syntax_assert_token_is(NewBreakKeyword, tok::kw_break, "break"); + return Data->replaceChild(NewBreakKeyword.getRaw(), + Cursor::BreakKeyword); +} + +TokenSyntax BreakStmtSyntax::getLabel() const { + return { Root, Data->getChild(Cursor::Label).get() }; +} + +BreakStmtSyntax BreakStmtSyntax::withLabel(TokenSyntax NewLabel) const { + assert(NewLabel.getTokenKind() == tok::identifier); + return Data->replaceChild(NewLabel.getRaw(), Cursor::Label); +} + +ContinueStmtSyntax ContinueStmtSyntax::makeBlank() { + return make( + RawSyntax::make(SyntaxKind::ContinueStmt, + { + RawTokenSyntax::missingToken(tok::kw_continue, "continue"), + RawTokenSyntax::missingToken(tok::identifier, ""), + }, + SourcePresence::Present)); } #pragma mark - continue-statement API -ContinueStmtSyntax::ContinueStmtSyntax(const RC Root, - ContinueStmtSyntaxData *Data) - : StmtSyntax(Root, Data) {} - -ContinueStmtSyntax ContinueStmtSyntax::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - auto Data = ContinueStmtSyntaxData::make(Raw, Parent, IndexInParent); - return { Data, Data.get() }; +void ContinueStmtSyntax::validate() const { + assert(Data->Raw->Layout.size() == 2); + syntax_assert_child_token_text(Data->Raw, + Cursor::ContinueKeyword, + tok::kw_continue, "continue"); + syntax_assert_child_token(Data->Raw, Cursor::Label, + tok::identifier); } -ContinueStmtSyntax ContinueStmtSyntax::makeBlank() { - auto Data = ContinueStmtSyntaxData::makeBlank(); - return { Data, Data.get() }; -} - -RC ContinueStmtSyntax::getContinueKeyword() const { - return cast(getRaw()->getChild(Cursor::ContinueKeyword)); +TokenSyntax ContinueStmtSyntax::getContinueKeyword() const { + return { Root, Data->getChild(Cursor::ContinueKeyword).get() }; } ContinueStmtSyntax ContinueStmtSyntax:: -withContinueKeyword(RC NewContinueKeyword) const { +withContinueKeyword(TokenSyntax NewContinueKeyword) const { syntax_assert_token_is(NewContinueKeyword, tok::kw_continue, "continue"); - return Data->replaceChild(NewContinueKeyword, + return Data->replaceChild(NewContinueKeyword.getRaw(), Cursor::ContinueKeyword); } -RC ContinueStmtSyntax::getLabel() const { - return cast(getRaw()->getChild(Cursor::Label)); +TokenSyntax ContinueStmtSyntax::getLabel() const { + return { Root, Data->getChild(Cursor::Label).get() }; } ContinueStmtSyntax -ContinueStmtSyntax::withLabel(RC NewLabel) const { - assert(NewLabel->getTokenKind() == tok::identifier); - return Data->replaceChild(NewLabel, Cursor::Label); -} - -#pragma mark - return-statement Data - -ReturnStmtSyntaxData::ReturnStmtSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : StmtSyntaxData(Raw, Parent, IndexInParent) { - assert(Raw->Layout.size() == 2); - syntax_assert_child_token_text(Raw, - ReturnStmtSyntax::Cursor::ReturnKeyword, - tok::kw_return, "return"); - assert(Raw->getChild(ReturnStmtSyntax::Cursor::Expression)->isExpr()); -} - -RC -ReturnStmtSyntaxData::make(RC Raw, const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new ReturnStmtSyntaxData { - Raw, Parent, IndexInParent - } - }; -} - -RC ReturnStmtSyntaxData::makeBlank() { - return make(RawSyntax::make(SyntaxKind::ReturnStmt, - { - TokenSyntax::missingToken(tok::kw_return, - "return"), - RawSyntax::missing(SyntaxKind::MissingExpr), - }, - SourcePresence::Present)); +ContinueStmtSyntax::withLabel(TokenSyntax NewLabel) const { + assert(NewLabel.getTokenKind() == tok::identifier); + return Data->replaceChild(NewLabel.getRaw(), Cursor::Label); } #pragma mark - return-statement API -ReturnStmtSyntax::ReturnStmtSyntax(const RC Root, - const ReturnStmtSyntaxData *Data) - : StmtSyntax(Root, Data) {} - -ReturnStmtSyntax ReturnStmtSyntax::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - auto Data = ReturnStmtSyntaxData::make(Raw, Parent, IndexInParent); - return { Data, Data.get() }; +void ReturnStmtSyntax::validate() const { + assert(Data->Raw->Layout.size() == 2); + syntax_assert_child_token_text(Data->Raw, + Cursor::ReturnKeyword, + tok::kw_return, "return"); + assert(Data->Raw->getChild(Cursor::Expression)->isExpr()); } ReturnStmtSyntax ReturnStmtSyntax::makeBlank() { - auto Data = ReturnStmtSyntaxData::makeBlank(); - return { Data, Data.get() }; + auto Raw = RawSyntax::make(SyntaxKind::ReturnStmt, + { + RawTokenSyntax::missingToken(tok::kw_return, + "return"), + RawSyntax::missing(SyntaxKind::MissingExpr), + }, + SourcePresence::Present); + return make(Raw); } -RC ReturnStmtSyntax::getReturnKeyword() const { - return cast(getRaw()->getChild(Cursor::ReturnKeyword)); +TokenSyntax ReturnStmtSyntax::getReturnKeyword() const { + return { Root, Data->getChild(Cursor::ReturnKeyword).get() }; } ReturnStmtSyntax ReturnStmtSyntax:: -withReturnKeyword(RC NewReturnKeyword) const { +withReturnKeyword(TokenSyntax NewReturnKeyword) const { syntax_assert_token_is(NewReturnKeyword, tok::kw_return, "return"); - return Data->replaceChild(NewReturnKeyword, + return Data->replaceChild(NewReturnKeyword.getRaw(), Cursor::ReturnKeyword); } Optional ReturnStmtSyntax::getExpression() const { - auto RawExpression = getRaw()->getChild(Cursor::Expression); - if (RawExpression->isMissing()) { - return llvm::None; - } - - auto *MyData = getUnsafeData(); - - auto &ChildPtr = *reinterpret_cast*>( - &MyData->CachedExpression); - - SyntaxData::realizeSyntaxNode(ChildPtr, RawExpression, MyData, - cursorIndex(Cursor::Expression)); - - return ExprSyntax { Root, MyData->CachedExpression.get() }; + return ExprSyntax { Root, Data->getChild(Cursor::Expression).get() }; } ReturnStmtSyntax @@ -373,10 +199,3 @@ ReturnStmtSyntax::withExpression(ExprSyntax NewExpression) const { return Data->replaceChild(NewExpression.getRaw(), Cursor::Expression); } - - -#pragma mark code-block API - -CodeBlockStmtSyntax::CodeBlockStmtSyntax(const RC Root, - CodeBlockStmtSyntaxData *Data) - : StmtSyntax(Root, Data) {} diff --git a/lib/Syntax/Syntax.cpp b/lib/Syntax/Syntax.cpp index bd4d91496ed..665318ff856 100644 --- a/lib/Syntax/Syntax.cpp +++ b/lib/Syntax/Syntax.cpp @@ -16,9 +16,6 @@ using namespace swift; using namespace swift::syntax; -Syntax::Syntax(const RC Root, const SyntaxData *Data) - : Root(Root), Data(Data) {} - RC Syntax::getRaw() const { return Data->getRaw(); } diff --git a/lib/Syntax/SyntaxData.cpp b/lib/Syntax/SyntaxData.cpp index b7da11459f3..75edefd0af0 100644 --- a/lib/Syntax/SyntaxData.cpp +++ b/lib/Syntax/SyntaxData.cpp @@ -10,11 +10,6 @@ // //===----------------------------------------------------------------------===// -#include "swift/Syntax/DeclSyntax.h" -#include "swift/Syntax/ExprSyntax.h" -#include "swift/Syntax/GenericSyntax.h" -#include "swift/Syntax/TypeSyntax.h" -#include "swift/Syntax/StmtSyntax.h" #include "swift/Syntax/UnknownSyntax.h" #include "llvm/Support/ErrorHandling.h" @@ -29,28 +24,6 @@ RC SyntaxData::make(RC Raw, }; } -RC SyntaxData::makeDataFromRaw(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - switch (Raw->Kind) { -#define SYNTAX(Id, ParentType) \ - case SyntaxKind::Id: \ - return Id##SyntaxData::make(Raw, Parent, IndexInParent); - -#define MISSING_SYNTAX(Id, ParentType) \ - case SyntaxKind::Id: \ - return ParentType##Data::make(Raw, Parent, IndexInParent); - -#define SYNTAX_COLLECTION(Id, Element) SYNTAX(Id, {}) - -#include "swift/Syntax/SyntaxKinds.def" - case SyntaxKind::Token: - llvm_unreachable("Can't make a SyntaxData from a Token!"); - } - - llvm_unreachable("Unhandled SyntaxKind in switch."); -} - bool SyntaxData::isType() const { return Raw->isType(); } @@ -67,6 +40,10 @@ bool SyntaxData::isExpr() const { return Raw->isExpr(); } +bool SyntaxData::isPattern() const { + return false; // FIXME: Raw->isPattern(); +} + bool SyntaxData::isUnknown() const { return Raw->isUnknown(); } diff --git a/lib/Syntax/SyntaxFactory.cpp b/lib/Syntax/SyntaxFactory.cpp index 7282391461e..a661a1af70b 100644 --- a/lib/Syntax/SyntaxFactory.cpp +++ b/lib/Syntax/SyntaxFactory.cpp @@ -24,38 +24,37 @@ using namespace swift; using namespace swift::syntax; UnknownSyntax -SyntaxFactory::makeUnknownSyntax(llvm::ArrayRef> Tokens) { +SyntaxFactory::makeUnknownSyntax(llvm::ArrayRef Tokens) { RawSyntax::LayoutList Layout; - std::copy(Tokens.begin(), Tokens.end(), std::back_inserter(Layout)); + for (auto &Token : Tokens) { + Layout.push_back(Token.getRaw()); + } auto Raw = RawSyntax::make(SyntaxKind::Unknown, Layout, SourcePresence::Present); - auto Data = UnknownSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } #pragma mark - Declarations #pragma mark - declaration-modifier -DeclModifierSyntax SyntaxFactory::makeDeclModifier(RC Name, - RC LeftParen, - RC Argument, - RC RightParen) { +DeclModifierSyntax SyntaxFactory::makeDeclModifier(TokenSyntax Name, + TokenSyntax LeftParen, + TokenSyntax Argument, + TokenSyntax RightParen) { auto Raw = RawSyntax::make(SyntaxKind::DeclModifier, { - Name, - LeftParen, - Argument, - RightParen, + Name.getRaw(), + LeftParen.getRaw(), + Argument.getRaw(), + RightParen.getRaw(), }, SourcePresence::Present); - auto Data = DeclModifierSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } DeclModifierSyntax SyntaxFactory::makeBlankDeclModifier() { - auto Data = DeclModifierSyntaxData::makeBlank(); - return { Data, Data.get() }; + return DeclModifierSyntax::makeBlank(); } #pragma mark - declaration-modifier-list @@ -69,106 +68,97 @@ makeDeclModifierList(const std::vector &Modifiers) { auto Raw = RawSyntax::make(SyntaxKind::DeclModifierList, Layout, SourcePresence::Present); - auto Data = DeclModifierListSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } DeclModifierListSyntax SyntaxFactory::makeBlankDeclModifierList() { - auto Data = DeclModifierListSyntaxData::makeBlank(); - return { Data, Data.get() }; + return DeclModifierListSyntax::makeBlank(); } #pragma mark - struct-declaration StructDeclSyntax -SyntaxFactory::makeStructDecl(RC StructToken, - RC Identifier, +SyntaxFactory::makeStructDecl(TokenSyntax StructToken, + TokenSyntax Identifier, Syntax GenericParameters, - Syntax WhereClause, RC LeftBrace, - Syntax DeclMembers, RC RightBrace) { + Syntax WhereClause, TokenSyntax LeftBrace, + Syntax DeclMembers, TokenSyntax RightBrace) { auto Raw = RawSyntax::make(SyntaxKind::StructDecl, { - StructToken, - Identifier, + StructToken.getRaw(), + Identifier.getRaw(), GenericParameters.getRaw(), WhereClause.getRaw(), - LeftBrace, + LeftBrace.getRaw(), DeclMembers.getRaw(), - RightBrace + RightBrace.getRaw() }, SourcePresence::Present); - auto Data = StructDeclSyntaxData::make(Raw); - return StructDeclSyntax { - Data, - Data.get() - }; + return make(Raw); } StructDeclSyntax SyntaxFactory::makeBlankStructDecl() { - auto Data = StructDeclSyntaxData::makeBlank(); - return StructDeclSyntax { - Data, Data.get() - }; + return StructDeclSyntax::makeBlank(); } #pragma mark - type-alias-declaration TypeAliasDeclSyntax SyntaxFactory::makeTypealiasDecl( - RC TypealiasToken, RC Identifier, - GenericParameterClauseSyntax GenericParams, RC AssignmentToken, + TokenSyntax TypealiasToken, TokenSyntax Identifier, + GenericParameterClauseSyntax GenericParams, TokenSyntax AssignmentToken, TypeSyntax Type) { auto Raw = RawSyntax::make(SyntaxKind::TypeAliasDecl, - {TypealiasToken, Identifier, GenericParams.getRaw(), - AssignmentToken, Type.getRaw()}, + { + TypealiasToken.getRaw(), + Identifier.getRaw(), + GenericParams.getRaw(), + AssignmentToken.getRaw(), + Type.getRaw() + }, SourcePresence::Present); - auto Data = TypeAliasDeclSyntaxData::make(Raw); - return TypeAliasDeclSyntax { Data, Data.get() }; + return make(Raw); } TypeAliasDeclSyntax SyntaxFactory::makeBlankTypealiasDecl() { - auto Data = TypeAliasDeclSyntaxData::makeBlank(); - return TypeAliasDeclSyntax { Data, Data.get() }; + return TypeAliasDeclSyntax::makeBlank(); } DeclMembersSyntax SyntaxFactory::makeBlankDeclMembers() { - auto Data = DeclMembersSyntaxData::makeBlank(); - return DeclMembersSyntax { Data, Data.get() }; + return DeclMembersSyntax::makeBlank(); } #pragma mark - function-parameter FunctionParameterSyntax SyntaxFactory:: -makeFunctionParameter(RC ExternalName, - RC LocalName, - RC Colon, +makeFunctionParameter(TokenSyntax ExternalName, + TokenSyntax LocalName, + TokenSyntax Colon, llvm::Optional ParameterTypeSyntax, - RC Ellipsis, - RC Equal, + TokenSyntax Ellipsis, + TokenSyntax Equal, llvm::Optional DefaultValue, - RC TrailingComma) { + TokenSyntax TrailingComma) { auto Raw = RawSyntax::make(SyntaxKind::FunctionParameter, { - ExternalName, - LocalName, - Colon, + ExternalName.getRaw(), + LocalName.getRaw(), + Colon.getRaw(), ParameterTypeSyntax.hasValue() ? ParameterTypeSyntax.getValue().getRaw() : RawSyntax::missing(SyntaxKind::MissingType), - Ellipsis, - Equal, + Ellipsis.getRaw(), + Equal.getRaw(), DefaultValue.hasValue() ? DefaultValue.getValue().getRaw() : RawSyntax::missing(SyntaxKind::MissingExpr), - TrailingComma, + TrailingComma.getRaw(), }, SourcePresence::Present); - auto Data = FunctionParameterSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } FunctionParameterSyntax SyntaxFactory::makeBlankFunctionParameter() { - auto Data = FunctionParameterSyntaxData::makeBlank(); - return { Data, Data.get() }; + return FunctionParameterSyntax::makeBlank(); } #pragma mark - function-parameter-list @@ -180,38 +170,35 @@ FunctionParameterListSyntax SyntaxFactory::makeFunctionParameterList( } FunctionParameterListSyntax SyntaxFactory::makeBlankFunctionParameterList() { - auto Data = FunctionParameterListSyntaxData::makeBlank(); - return { Data, Data.get() }; + return FunctionParameterListSyntax::makeBlank(); } #pragma mark - function-signature FunctionSignatureSyntax -SyntaxFactory::makeFunctionSignature(RC LeftParen, +SyntaxFactory::makeFunctionSignature(TokenSyntax LeftParen, FunctionParameterListSyntax ParameterList, - RC RightParen, - RC ThrowsOrRethrows, - RC Arrow, + TokenSyntax RightParen, + TokenSyntax ThrowsOrRethrows, + TokenSyntax Arrow, TypeAttributesSyntax ReturnTypeAttributes, TypeSyntax ReturnTypeSyntax) { auto Raw = RawSyntax::make(SyntaxKind::FunctionSignature, { - LeftParen, + LeftParen.getRaw(), ParameterList.getRaw(), - RightParen, - ThrowsOrRethrows, - Arrow, + RightParen.getRaw(), + ThrowsOrRethrows.getRaw(), + Arrow.getRaw(), ReturnTypeAttributes.getRaw(), ReturnTypeSyntax.getRaw() }, SourcePresence::Present); - auto Data = FunctionSignatureSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } FunctionSignatureSyntax SyntaxFactory::makeBlankFunctionSignature() { - auto Data = FunctionSignatureSyntaxData::makeBlank(); - return { Data, Data.get() }; + return FunctionSignatureSyntax::makeBlank(); } #pragma mark - function-declaration @@ -219,8 +206,8 @@ FunctionSignatureSyntax SyntaxFactory::makeBlankFunctionSignature() { FunctionDeclSyntax SyntaxFactory:: makeFunctionDecl(TypeAttributesSyntax Attributes, DeclModifierListSyntax Modifiers, - RC FuncKeyword, - RC Identifier, + TokenSyntax FuncKeyword, + TokenSyntax Identifier, llvm::Optional GenericParams, FunctionSignatureSyntax Signature, llvm::Optional GenericWhereClause, @@ -229,8 +216,8 @@ makeFunctionDecl(TypeAttributesSyntax Attributes, { Attributes.getRaw(), Modifiers.getRaw(), - FuncKeyword, - Identifier, + FuncKeyword.getRaw(), + Identifier.getRaw(), GenericParams.hasValue() ? GenericParams.getValue().getRaw() : SyntaxFactory::makeBlankGenericParameterClause().getRaw(), @@ -243,48 +230,42 @@ makeFunctionDecl(TypeAttributesSyntax Attributes, : SyntaxFactory::makeBlankCodeBlock().getRaw() }, SourcePresence::Present); - auto Data = FunctionDeclSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } FunctionDeclSyntax SyntaxFactory::makeBlankFunctionDecl() { - auto Data = FunctionDeclSyntaxData::makeBlank(); - return { Data, Data.get() }; + return FunctionDeclSyntax::makeBlank(); } #pragma mark - Statements CodeBlockStmtSyntax -SyntaxFactory::makeCodeBlock(RC LeftBraceToken, +SyntaxFactory::makeCodeBlock(TokenSyntax LeftBraceToken, StmtListSyntax Elements, - RC RightBraceToken) { + TokenSyntax RightBraceToken) { auto Raw = RawSyntax::make(SyntaxKind::CodeBlockStmt, { - LeftBraceToken, + LeftBraceToken.getRaw(), Elements.getRaw(), - RightBraceToken + RightBraceToken.getRaw() }, SourcePresence::Present); - auto Data = CodeBlockStmtSyntaxData::make(Raw); - return CodeBlockStmtSyntax { Data, Data.get() }; + return make(Raw); } CodeBlockStmtSyntax SyntaxFactory::makeBlankCodeBlock() { - auto Data = CodeBlockStmtSyntaxData::makeBlank(); - return CodeBlockStmtSyntax { Data, Data.get() }; + return CodeBlockStmtSyntax::makeBlank(); } FallthroughStmtSyntax -SyntaxFactory::makeFallthroughStmt(RC FallthroughKeyword) { +SyntaxFactory::makeFallthroughStmt(TokenSyntax FallthroughKeyword) { auto Raw = RawSyntax::make(SyntaxKind::FallthroughStmt, { - FallthroughKeyword + FallthroughKeyword.getRaw() }, SourcePresence::Present); - auto Data = FallthroughStmtSyntaxData::make(Raw); - return FallthroughStmtSyntax { Data, Data.get() }; + return make(Raw); } FallthroughStmtSyntax SyntaxFactory::makeBlankFallthroughStmt() { - auto Data = FallthroughStmtSyntaxData::makeBlank(); - return FallthroughStmtSyntax { Data, Data.get() }; + return FallthroughStmtSyntax::makeBlank(); } #pragma mark - break-statement @@ -292,45 +273,41 @@ FallthroughStmtSyntax SyntaxFactory::makeBlankFallthroughStmt() { /// Make a break statement with the give `break` keyword and /// destination label. BreakStmtSyntax -SyntaxFactory::makeBreakStmt(RC BreakKeyword, - RC Label) { +SyntaxFactory::makeBreakStmt(TokenSyntax BreakKeyword, + TokenSyntax Label) { auto Raw = RawSyntax::make(SyntaxKind::BreakStmt, { - BreakKeyword, - Label, + BreakKeyword.getRaw(), + Label.getRaw(), }, SourcePresence::Present); - auto Data = BreakStmtSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } /// Make a break statement with the `break` keyword /// and destination label marked as missing. BreakStmtSyntax SyntaxFactory::makeBlankBreakStmtSyntax() { - auto Data = BreakStmtSyntaxData::makeBlank(); - return { Data, Data.get() }; + return BreakStmtSyntax::makeBlank(); } #pragma mark - continue-statement ContinueStmtSyntax -SyntaxFactory::makeContinueStmt(RC ContinueKeyword, - RC Label) { +SyntaxFactory::makeContinueStmt(TokenSyntax ContinueKeyword, + TokenSyntax Label) { auto Raw = RawSyntax::make(SyntaxKind::BreakStmt, { - ContinueKeyword, - Label, + ContinueKeyword.getRaw(), + Label.getRaw(), }, SourcePresence::Present); - auto Data = ContinueStmtSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } /// Make a break statement with the `break` keyword /// and destination label marked as missing. ContinueStmtSyntax SyntaxFactory::makeBlankContinueStmtSyntax() { - auto Data = ContinueStmtSyntaxData::makeBlank(); - return { Data, Data.get() }; + return ContinueStmtSyntax::makeBlank(); } #pragma mark - return-statement @@ -338,27 +315,25 @@ ContinueStmtSyntax SyntaxFactory::makeBlankContinueStmtSyntax() { /// Make a return statement with the given `return` keyword and returned /// expression. ReturnStmtSyntax -SyntaxFactory::makeReturnStmt(RC ReturnKeyword, +SyntaxFactory::makeReturnStmt(TokenSyntax ReturnKeyword, ExprSyntax ReturnedExpression) { auto Raw = RawSyntax::make(SyntaxKind::ReturnStmt, { - ReturnKeyword, + ReturnKeyword.getRaw(), ReturnedExpression.getRaw(), }, SourcePresence::Present); - auto Data = ReturnStmtSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } ReturnStmtSyntax SyntaxFactory::makeBlankReturnStmt() { auto Raw = RawSyntax::make(SyntaxKind::ReturnStmt, { - TokenSyntax::missingToken(tok::kw_return, "return"), + RawTokenSyntax::missingToken(tok::kw_return, "return"), RawSyntax::missing(SyntaxKind::MissingExpr), }, SourcePresence::Present); - auto Data = ReturnStmtSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } /// Make a statement list from a loosely connected list of statements. @@ -371,15 +346,13 @@ SyntaxFactory::makeStmtList(const std::vector &Statements) { auto Raw = RawSyntax::make(SyntaxKind::StmtList, Layout, SourcePresence::Present); - auto Data = StmtListSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } /// Make an empty statement list. StmtListSyntax SyntaxFactory::makeBlankStmtList() { auto Raw = RawSyntax::make(SyntaxKind::StmtList, {}, SourcePresence::Present); - auto Data = StmtListSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } #pragma mark - Expressions @@ -387,73 +360,67 @@ StmtListSyntax SyntaxFactory::makeBlankStmtList() { #pragma mark - integer-literal-expression IntegerLiteralExprSyntax -SyntaxFactory::makeIntegerLiteralExpr(RC Sign, - RC Digits) { +SyntaxFactory::makeIntegerLiteralExpr(TokenSyntax Sign, + TokenSyntax Digits) { auto Raw = RawSyntax::make(SyntaxKind::IntegerLiteralExpr, { - Sign, - Digits, + Sign.getRaw(), + Digits.getRaw(), }, SourcePresence::Present); - auto Data = IntegerLiteralExprSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } IntegerLiteralExprSyntax SyntaxFactory::makeBlankIntegerLiteralExpr() { auto Raw = RawSyntax::make(SyntaxKind::IntegerLiteralExpr, { - TokenSyntax::missingToken(tok::oper_prefix, "-"), - TokenSyntax::missingToken(tok::integer_literal, ""), + RawTokenSyntax::missingToken(tok::oper_prefix, "-"), + RawTokenSyntax::missingToken(tok::integer_literal, ""), }, SourcePresence::Present); - auto Data = IntegerLiteralExprSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } #pragma mark - symbolic-reference SymbolicReferenceExprSyntax -SyntaxFactory::makeSymbolicReferenceExpr(RC Identifier, +SyntaxFactory::makeSymbolicReferenceExpr(TokenSyntax Identifier, llvm::Optional GenericArgs) { auto Raw = RawSyntax::make(SyntaxKind::SymbolicReferenceExpr, { - Identifier, + Identifier.getRaw(), GenericArgs.hasValue() ? GenericArgs.getValue().getRaw() : RawSyntax::missing(SyntaxKind::GenericArgumentClause) }, SourcePresence::Present); - auto Data = SymbolicReferenceExprSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } SymbolicReferenceExprSyntax SyntaxFactory::makeBlankSymbolicReferenceExpr() { - auto Data = SymbolicReferenceExprSyntaxData::makeBlank(); - return { Data, Data.get() }; + return SymbolicReferenceExprSyntax::makeBlank(); } #pragma mark - function-call-argument FunctionCallArgumentSyntax SyntaxFactory::makeBlankFunctionCallArgument() { - auto Data = FunctionCallArgumentSyntaxData::makeBlank(); - return { Data, Data.get() }; + return FunctionCallArgumentSyntax::makeBlank(); } FunctionCallArgumentSyntax -SyntaxFactory::makeFunctionCallArgument(RC Label, - RC Colon, +SyntaxFactory::makeFunctionCallArgument(TokenSyntax Label, + TokenSyntax Colon, ExprSyntax ExpressionArgument, - RC TrailingComma) { + TokenSyntax TrailingComma) { auto Raw = RawSyntax::make(SyntaxKind::FunctionCallArgument, { - Label, - Colon, + Label.getRaw(), + Colon.getRaw(), ExpressionArgument.getRaw(), - TrailingComma + TrailingComma.getRaw() }, SourcePresence::Present); - auto Data = FunctionCallArgumentSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } #pragma mark - function-call-argument-list @@ -469,380 +436,291 @@ SyntaxFactory::makeFunctionCallArgumentList( auto Raw = RawSyntax::make(SyntaxKind::FunctionCallArgumentList, Layout, SourcePresence::Present); - auto Data = FunctionCallArgumentListSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } FunctionCallArgumentListSyntax SyntaxFactory::makeBlankFunctionCallArgumentList() { - auto Data = FunctionCallArgumentListSyntaxData::makeBlank(); - return { Data, Data.get() }; + return FunctionCallArgumentListSyntax::makeBlank(); } #pragma mark - function-call-expression FunctionCallExprSyntax SyntaxFactory::makeFunctionCallExpr(ExprSyntax CalledExpr, - RC LeftParen, + TokenSyntax LeftParen, FunctionCallArgumentListSyntax Arguments, - RC RightParen) { + TokenSyntax RightParen) { auto Raw = RawSyntax::make(SyntaxKind::FunctionCallExpr, { CalledExpr.getRaw(), - LeftParen, + LeftParen.getRaw(), Arguments.getRaw(), - RightParen + RightParen.getRaw() }, SourcePresence::Present); - auto Data = FunctionCallExprSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } FunctionCallExprSyntax SyntaxFactory::makeBlankFunctionCallExpr() { - auto Data = FunctionCallExprSyntaxData::makeBlank(); - return { Data, Data.get() }; + return FunctionCallExprSyntax::makeBlank(); } #pragma mark - Tokens -RC +TokenSyntax +SyntaxFactory::makeToken(tok Kind, OwnedString Text, SourcePresence Presence, + const Trivia &LeadingTrivia, + const Trivia &TrailingTrivia) { + return make(RawTokenSyntax::make(Kind, Text, Presence, + LeadingTrivia, TrailingTrivia)); +} + +TokenSyntax SyntaxFactory::makeStaticKeyword(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return TokenSyntax::make(tok::kw_static, "static", - SourcePresence::Present, - LeadingTrivia, TrailingTrivia); + + return makeToken(tok::kw_static, "static", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC +TokenSyntax SyntaxFactory::makePublicKeyword(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return TokenSyntax::make(tok::kw_public, "public", - SourcePresence::Present, - LeadingTrivia, TrailingTrivia); + return makeToken(tok::kw_public, "public", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC +TokenSyntax SyntaxFactory::makeFuncKeyword(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return TokenSyntax::make(tok::kw_func, "func", - SourcePresence::Present, - LeadingTrivia, TrailingTrivia); + return makeToken(tok::kw_func, "func", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC +TokenSyntax SyntaxFactory::makeFallthroughKeyword(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return TokenSyntax::make(tok::kw_fallthrough, "fallthrough", - SourcePresence::Present, - LeadingTrivia, TrailingTrivia); + return makeToken(tok::kw_fallthrough, "fallthrough", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC +TokenSyntax SyntaxFactory::makeAtSignToken(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return TokenSyntax::make(tok::at_sign, "@", SourcePresence::Present, - LeadingTrivia, TrailingTrivia); + return makeToken(tok::at_sign, "@", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC +TokenSyntax SyntaxFactory::makeBreakKeyword(const swift::syntax::Trivia &LeadingTrivia, const swift::syntax::Trivia &TrailingTrivia) { - return TokenSyntax::make(tok::kw_break, "break", SourcePresence::Present, - LeadingTrivia, TrailingTrivia); + return makeToken(tok::kw_break, "break", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC SyntaxFactory:: +TokenSyntax SyntaxFactory:: makeContinueKeyword(const swift::syntax::Trivia &LeadingTrivia, const swift::syntax::Trivia &TrailingTrivia) { - return TokenSyntax::make(tok::kw_continue, "continue", - SourcePresence::Present, - LeadingTrivia, TrailingTrivia); + return makeToken(tok::kw_continue, "continue", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC SyntaxFactory:: +TokenSyntax SyntaxFactory:: makeReturnKeyword(const swift::syntax::Trivia &LeadingTrivia, const swift::syntax::Trivia &TrailingTrivia) { - return TokenSyntax::make(tok::kw_return, "return", - SourcePresence::Present, - LeadingTrivia, TrailingTrivia); + return makeToken(tok::kw_return, "return", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC +TokenSyntax SyntaxFactory::makeLeftAngleToken(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return TokenSyntax::make(tok::l_angle, "<", SourcePresence::Present, - LeadingTrivia, TrailingTrivia); + return makeToken(tok::l_angle, "<", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC +TokenSyntax SyntaxFactory::makeRightAngleToken(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return TokenSyntax::make(tok::r_angle, ">", SourcePresence::Present, - LeadingTrivia, TrailingTrivia); + return makeToken(tok::r_angle, ">", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC +TokenSyntax SyntaxFactory::makeLeftParenToken(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return TokenSyntax::make(tok::l_paren, "(", SourcePresence::Present, - LeadingTrivia, TrailingTrivia); + return makeToken(tok::l_paren, "(", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC +TokenSyntax SyntaxFactory::makeRightParenToken(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return TokenSyntax::make(tok::r_paren, ")", SourcePresence::Present, - LeadingTrivia, TrailingTrivia); + return makeToken(tok::r_paren, ")", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC +TokenSyntax SyntaxFactory::makeLeftBraceToken(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return TokenSyntax::make(tok::l_brace, "{", SourcePresence::Present, - LeadingTrivia, TrailingTrivia); + return makeToken(tok::l_brace, "{", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC +TokenSyntax SyntaxFactory::makeRightBraceToken(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return TokenSyntax::make(tok::r_brace, "}", SourcePresence::Present, - LeadingTrivia, TrailingTrivia); + return makeToken(tok::r_brace, "}", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC +TokenSyntax SyntaxFactory::makeLeftSquareBracketToken(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return TokenSyntax::make(tok::l_square, "[", SourcePresence::Present, - LeadingTrivia, TrailingTrivia); + return makeToken(tok::l_square, "[", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC +TokenSyntax SyntaxFactory::makeRightSquareBracketToken(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return TokenSyntax::make(tok::r_square, "]", SourcePresence::Present, - LeadingTrivia, TrailingTrivia); + return makeToken(tok::r_square, "]", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC +TokenSyntax SyntaxFactory::makeQuestionPostfixToken(const Trivia &TrailingTrivia) { - return TokenSyntax::make(tok::question_postfix, "?", SourcePresence::Present, - {}, TrailingTrivia); + return makeToken(tok::question_postfix, "?", SourcePresence::Present, + {}, TrailingTrivia); } -RC +TokenSyntax SyntaxFactory::makeExclaimPostfixToken(const Trivia &TrailingTrivia) { - return TokenSyntax::make(tok::exclaim_postfix, "!", SourcePresence::Present, - {}, TrailingTrivia); + return makeToken(tok::exclaim_postfix, "!", SourcePresence::Present, + {}, TrailingTrivia); } -RC SyntaxFactory::makeIdentifier(OwnedString Name, +TokenSyntax SyntaxFactory::makeIdentifier(OwnedString Name, const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return RC{ - new TokenSyntax { - tok::identifier, Name, - SourcePresence::Present, - LeadingTrivia, - TrailingTrivia - } - }; + return makeToken(tok::identifier, Name, SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC SyntaxFactory::makeCommaToken(const Trivia &LeadingTrivia, +TokenSyntax SyntaxFactory::makeCommaToken(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return RC{ - new TokenSyntax{tok::comma, ",", - SourcePresence::Present, - LeadingTrivia, - TrailingTrivia - } - }; + return makeToken(tok::comma, ",", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC SyntaxFactory::makeColonToken(const Trivia &LeadingTrivia, +TokenSyntax SyntaxFactory::makeColonToken(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return RC { - new TokenSyntax{tok::colon, ":", - SourcePresence::Present, - LeadingTrivia, - TrailingTrivia - } - }; + return makeToken(tok::colon, ":", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC SyntaxFactory::makeDotToken(const Trivia &LeadingTrivia, +TokenSyntax SyntaxFactory::makeDotToken(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return RC { - new TokenSyntax { - tok::period, ".", - SourcePresence::Present, - LeadingTrivia, - TrailingTrivia, - } - }; + return makeToken(tok::period, ".", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC SyntaxFactory::makeStructKeyword(const Trivia &LeadingTrivia, +TokenSyntax SyntaxFactory::makeStructKeyword(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return RC { - new TokenSyntax{tok::kw_struct, "struct", - SourcePresence::Present, - LeadingTrivia, - TrailingTrivia - } - }; + return makeToken(tok::kw_struct, "struct", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC SyntaxFactory::makeWhereKeyword(const Trivia &LeadingTrivia, +TokenSyntax SyntaxFactory::makeWhereKeyword(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return RC { - new TokenSyntax{tok::kw_where, "where", - SourcePresence::Present, - LeadingTrivia, - TrailingTrivia - } - }; + return makeToken(tok::kw_where, "where", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC SyntaxFactory::makeInoutKeyword(const Trivia &LeadingTrivia, +TokenSyntax SyntaxFactory::makeInoutKeyword(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return RC { - new TokenSyntax{tok::kw_inout, "inout", - SourcePresence::Present, - LeadingTrivia, - TrailingTrivia - } - }; + return makeToken(tok::kw_inout, "inout", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC +TokenSyntax SyntaxFactory::makeThrowsKeyword(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return RC { - new TokenSyntax { - tok::kw_throws, "throws", - SourcePresence::Present, - LeadingTrivia, - TrailingTrivia - } - }; + return makeToken(tok::kw_throws, "throws", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC +TokenSyntax SyntaxFactory::makeRethrowsKeyword(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return RC { - new TokenSyntax { - tok::kw_rethrows, "rethrows", - SourcePresence::Present, - LeadingTrivia, - TrailingTrivia - } - }; + return makeToken(tok::kw_rethrows, "rethrows", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC +TokenSyntax SyntaxFactory::makeTypealiasKeyword(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return RC { - new TokenSyntax { - tok::kw_typealias, "typealias", - SourcePresence::Present, - LeadingTrivia, - TrailingTrivia - } - }; + return makeToken(tok::kw_typealias, "typealias", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC +TokenSyntax SyntaxFactory::makeEqualToken(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return RC { - new TokenSyntax{tok::equal, "=", - SourcePresence::Present, - LeadingTrivia, - TrailingTrivia - } - }; + return makeToken(tok::equal, "=", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC SyntaxFactory::makeArrow(const Trivia &LeadingTrivia, +TokenSyntax SyntaxFactory::makeArrow(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return RC { - new TokenSyntax{tok::arrow, "->", - SourcePresence::Present, - LeadingTrivia, - TrailingTrivia - } - }; + return makeToken(tok::arrow, "->", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC +TokenSyntax SyntaxFactory::makeEqualityOperator(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return RC { - new TokenSyntax { - tok::oper_binary_spaced, "==", - SourcePresence::Present, - LeadingTrivia, - TrailingTrivia - } - }; + return makeToken(tok::oper_binary_spaced, "==", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC SyntaxFactory::makeTypeToken(const Trivia &LeadingTrivia, +TokenSyntax SyntaxFactory::makeTypeToken(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return RC { - new TokenSyntax { - tok::identifier, "Type", - SourcePresence::Present, - LeadingTrivia, - TrailingTrivia - } - }; + return makeToken(tok::identifier, "Type", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC +TokenSyntax SyntaxFactory::makeProtocolToken(const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return RC { - new TokenSyntax{tok::identifier, "Protocol", - SourcePresence::Present, - LeadingTrivia, - TrailingTrivia - } - }; + return makeToken(tok::identifier, "Protocol", SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } -RC +TokenSyntax SyntaxFactory::makeIntegerLiteralToken(OwnedString Digits, const Trivia &LeadingTrivia, const Trivia &TrailingTrivia) { - return RC { - new TokenSyntax(tok::integer_literal, Digits, SourcePresence::Present, - LeadingTrivia, - TrailingTrivia) - }; + return makeToken(tok::integer_literal, Digits, SourcePresence::Present, + LeadingTrivia, TrailingTrivia); } #pragma mark - Generics GenericParameterClauseSyntax SyntaxFactory::makeBlankGenericParameterClause() { - auto Data = GenericParameterClauseSyntaxData::makeBlank(); - return GenericParameterClauseSyntax { Data, Data.get() }; + return GenericParameterClauseSyntax::makeBlank(); } GenericArgumentClauseSyntax SyntaxFactory::makeBlankGenericArgumentClause() { - auto Data = GenericArgumentClauseSyntaxData::makeBlank(); - return { Data, Data.get() }; + return GenericArgumentClauseSyntax::makeBlank(); } GenericWhereClauseSyntax SyntaxFactory::makeBlankGenericWhereClause() { - auto Data = GenericWhereClauseSyntaxData::makeBlank(); - return GenericWhereClauseSyntax { Data, Data.get() }; + return GenericWhereClauseSyntax::makeBlank(); } GenericParameterSyntax @@ -851,35 +729,34 @@ SyntaxFactory::makeGenericParameter(OwnedString TypeName, const Trivia &TrailingTrivia) { auto Raw = RawSyntax::make(SyntaxKind::GenericParameter, { - SyntaxFactory::makeIdentifier(TypeName, - LeadingTrivia, - TrailingTrivia), - TokenSyntax::missingToken(tok::colon, ":"), + RawTokenSyntax::make(tok::identifier, + TypeName, + SourcePresence::Present, + LeadingTrivia, + TrailingTrivia), + RawTokenSyntax::missingToken(tok::colon, ":"), RawSyntax::missing(SyntaxKind::TypeIdentifier), }, SourcePresence::Present); - auto Data = GenericParameterSyntaxData::make(Raw); - return GenericParameterSyntax { Data, Data.get() }; + return make(Raw); } SameTypeRequirementSyntax SyntaxFactory:: makeSameTypeRequirement( TypeIdentifierSyntax LeftTypeIdentifier, - RC EqualityToken, + TokenSyntax EqualityToken, TypeSyntax RightType) { auto Raw = RawSyntax::make(SyntaxKind::SameTypeRequirement, { LeftTypeIdentifier.getRaw(), - EqualityToken, + EqualityToken.getRaw(), RightType.getRaw() }, SourcePresence::Present); - auto Data = SameTypeRequirementSyntaxData::make(Raw); - return SameTypeRequirementSyntax { Data, Data.get() }; + return make(Raw); } SameTypeRequirementSyntax SyntaxFactory::makeBlankSameTypeRequirement() { - auto Data = SameTypeRequirementSyntaxData::makeBlank(); - return SameTypeRequirementSyntax { Data, Data.get() }; + return SameTypeRequirementSyntax::makeBlank(); } GenericRequirementListSyntax SyntaxFactory:: @@ -890,23 +767,21 @@ makeGenericRequirementList(std::vector &Requirements){ } auto Raw = RawSyntax::make(SyntaxKind::GenericRequirementList, Layout, SourcePresence::Present); - auto Data = GenericRequirementListSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } GenericRequirementListSyntax SyntaxFactory::makeBlankGenericRequirementList() { - auto Data = GenericRequirementListSyntaxData::makeBlank(); - return { Data, Data.get() }; + return GenericRequirementListSyntax::makeBlank(); } #pragma mark - Operators /// Make a prefix operator with the given text. -RC +TokenSyntax SyntaxFactory::makePrefixOperator(OwnedString Name, const Trivia &LeadingTrivia) { - return TokenSyntax::make(tok::oper_prefix, Name, - SourcePresence::Present, LeadingTrivia, {}); + return makeToken(tok::oper_prefix, Name, + SourcePresence::Present, LeadingTrivia, {}); } #pragma mark - Types @@ -914,27 +789,25 @@ SyntaxFactory::makePrefixOperator(OwnedString Name, #pragma mark - type-attribute TypeAttributeSyntax -SyntaxFactory::makeTypeAttribute(RC AtSignToken, - RC Identifier, - RC LeftParen, +SyntaxFactory::makeTypeAttribute(TokenSyntax AtSignToken, + TokenSyntax Identifier, + TokenSyntax LeftParen, BalancedTokensSyntax BalancedTokens, - RC RightParen) { + TokenSyntax RightParen) { auto Raw = RawSyntax::make(SyntaxKind::TypeAttribute, { - AtSignToken, - Identifier, - LeftParen, + AtSignToken.getRaw(), + Identifier.getRaw(), + LeftParen.getRaw(), BalancedTokens.getRaw(), - RightParen, + RightParen.getRaw(), }, SourcePresence::Present); - auto Data = TypeAttributeSyntaxData::make(Raw); - return TypeAttributeSyntax { Data, Data.get() }; + return make(Raw); } TypeAttributeSyntax SyntaxFactory::makeBlankTypeAttribute() { - auto Data = TypeAttributeSyntaxData::makeBlank(); - return TypeAttributeSyntax { Data, Data.get() }; + return TypeAttributeSyntax::makeBlank(); } #pragma mark - type-attributes @@ -942,17 +815,19 @@ TypeAttributeSyntax SyntaxFactory::makeBlankTypeAttribute() { #pragma mark - balanced-tokens BalancedTokensSyntax -SyntaxFactory::makeBalancedTokens(RawSyntax::LayoutList Tokens) { +SyntaxFactory::makeBalancedTokens(llvm::ArrayRef Tokens) { + RawSyntax::LayoutList RawTokens; + for (auto &Tok : Tokens) { + RawTokens.push_back(Tok.getRaw()); + } auto Raw = RawSyntax::make(SyntaxKind::BalancedTokens, - Tokens, + RawTokens, SourcePresence::Present); - auto Data = BalancedTokensSyntaxData::make(Raw); - return BalancedTokensSyntax { Data, Data.get() }; + return make(Raw); } BalancedTokensSyntax SyntaxFactory::makeBlankBalancedTokens() { - auto Data = BalancedTokensSyntaxData::makeBlank(); - return BalancedTokensSyntax { Data, Data.get() }; + return BalancedTokensSyntax::makeBlank(); } #pragma mark - type-identifier @@ -964,40 +839,40 @@ SyntaxFactory::makeTypeIdentifier(OwnedString Name, auto Raw = RawSyntax::make( SyntaxKind::TypeIdentifier, { - SyntaxFactory::makeIdentifier(Name, LeadingTrivia, TrailingTrivia), + RawTokenSyntax::make(tok::identifier, + Name, + SourcePresence::Present, + LeadingTrivia, + TrailingTrivia), RawSyntax::missing(SyntaxKind::GenericArgumentClause), - TokenSyntax::missingToken(tok::period, "."), + RawTokenSyntax::missingToken(tok::period, "."), RawSyntax::missing(SyntaxKind::TypeIdentifier), }, SourcePresence::Present); - auto Data = TypeIdentifierSyntaxData::make(Raw); - return TypeIdentifierSyntax { Data, Data.get() }; + return make(Raw); } TypeIdentifierSyntax SyntaxFactory::makeAnyTypeIdentifier() { - auto Data = TypeIdentifierSyntaxData::makeBlank(); - return TypeIdentifierSyntax { Data, Data.get() } - .withIdentifier(makeIdentifier("Any", {}, {})); + return TypeIdentifierSyntax::makeBlank() + .withIdentifier(makeIdentifier("Any", {}, {})); } TypeIdentifierSyntax SyntaxFactory::makeSelfTypeIdentifier() { - auto Data = TypeIdentifierSyntaxData::makeBlank(); - return TypeIdentifierSyntax { Data, Data.get() } - .withIdentifier(makeIdentifier("Self", {}, {})); + return TypeIdentifierSyntax::makeBlank() + .withIdentifier(makeIdentifier("Self", {}, {})); } TypeIdentifierSyntax -SyntaxFactory::makeTypeIdentifier(RC Identifier, +SyntaxFactory::makeTypeIdentifier(TokenSyntax Identifier, GenericArgumentClauseSyntax GenericArgs) { auto Raw = RawSyntax::make(SyntaxKind::TypeIdentifier, { - Identifier, GenericArgs.getRaw(), - TokenSyntax::missingToken(tok::period, "."), + Identifier.getRaw(), GenericArgs.getRaw(), + RawTokenSyntax::missingToken(tok::period, "."), RawSyntax::missing(SyntaxKind::TypeIdentifier), }, SourcePresence::Present); - auto Data = TypeIdentifierSyntaxData::make(Raw); - return TypeIdentifierSyntax { Data, Data.get() }; + return make(Raw); } #pragma mark - tuple-type @@ -1005,43 +880,34 @@ SyntaxFactory::makeTypeIdentifier(RC Identifier, TupleTypeSyntax SyntaxFactory::makeVoidTupleType() { auto Raw = RawSyntax::make(SyntaxKind::TupleType, { - SyntaxFactory::makeLeftParenToken({}, {}), + SyntaxFactory::makeLeftParenToken({}, {}).getRaw(), RawSyntax::missing(SyntaxKind::TupleTypeElementList), - SyntaxFactory::makeRightParenToken({}, {}), + SyntaxFactory::makeRightParenToken({}, {}).getRaw(), }, SourcePresence::Present); - auto Data = TupleTypeSyntaxData::make(std::move(Raw)); - return TupleTypeSyntax { - Data, Data.get() - }; + return make(Raw); } TupleTypeSyntax -SyntaxFactory::makeTupleType(RC LParen, +SyntaxFactory::makeTupleType(TokenSyntax LParen, TupleTypeElementListSyntax Elements, - RC RParen) { + TokenSyntax RParen) { auto Raw = RawSyntax::make(SyntaxKind::TupleType, - { LParen, Elements.getRaw(), RParen }, + { LParen.getRaw(), + Elements.getRaw(), + RParen.getRaw() }, SourcePresence::Present); - auto Data = TupleTypeSyntaxData::make(std::move(Raw)); - return TupleTypeSyntax { - Data, Data.get() - }; + return make(Raw); } TupleTypeElementSyntax -SyntaxFactory::makeTupleTypeElement(RC Name, - RC Colon, +SyntaxFactory::makeTupleTypeElement(TokenSyntax Name, + TokenSyntax Colon, TypeSyntax ElementTypeSyntax, - Optional> MaybeComma) { - auto Data = TupleTypeElementSyntaxData::makeBlank(); - RC Comma; - if (MaybeComma.hasValue()) { - Comma = MaybeComma.getValue(); - } else { - Comma = TokenSyntax::missingToken(tok::comma, ","); - } - return TupleTypeElementSyntax { Data, Data.get() } + Optional MaybeComma) { + TokenSyntax Comma = MaybeComma.getValueOr( + TokenSyntax::missingToken(tok::comma, ",")); + return TupleTypeElementSyntax::makeBlank() .withLabel(Name) .withColonToken(Colon) .withTypeSyntax(ElementTypeSyntax) @@ -1051,15 +917,10 @@ SyntaxFactory::makeTupleTypeElement(RC Name, TupleTypeElementSyntax SyntaxFactory::makeTupleTypeElement(TypeSyntax ElementType, - Optional> MaybeComma) { - auto Data = TupleTypeElementSyntaxData::makeBlank(); - RC Comma; - if (MaybeComma.hasValue()) { - Comma = MaybeComma.getValue(); - } else { - Comma = TokenSyntax::missingToken(tok::comma, ","); - } - return TupleTypeElementSyntax { Data, Data.get() } + Optional MaybeComma) { + TokenSyntax Comma = MaybeComma.getValueOr( + TokenSyntax::missingToken(tok::comma, ",")); + return TupleTypeElementSyntax::makeBlank() .withTypeSyntax(ElementType) .withCommaToken(Comma); } @@ -1079,17 +940,15 @@ SyntaxFactory::makeOptionalType(TypeSyntax BaseType, auto Raw = RawSyntax::make(SyntaxKind::OptionalType, { BaseType.getRaw(), - SyntaxFactory::makeQuestionPostfixToken(TrailingTrivia), + SyntaxFactory::makeQuestionPostfixToken(TrailingTrivia).getRaw(), }, SourcePresence::Present); - auto Data = OptionalTypeSyntaxData::make(Raw); - return OptionalTypeSyntax { Data, Data.get() }; + return make(Raw); } OptionalTypeSyntax SyntaxFactory::makeBlankOptionalType() { - auto Data = OptionalTypeSyntaxData::makeBlank(); - return OptionalTypeSyntax { Data, Data.get() }; + return OptionalTypeSyntax::makeBlank(); } #pragma mark - implicitly-unwrapped-optional-type @@ -1100,181 +959,166 @@ makeImplicitlyUnwrappedOptionalType(TypeSyntax BaseType, auto Raw = RawSyntax::make(SyntaxKind::ImplicitlyUnwrappedOptionalType, { BaseType.getRaw(), - SyntaxFactory::makeExclaimPostfixToken(TrailingTrivia), + SyntaxFactory::makeExclaimPostfixToken(TrailingTrivia).getRaw(), }, SourcePresence::Present); - auto Data = ImplicitlyUnwrappedOptionalTypeSyntaxData::make(Raw); - return ImplicitlyUnwrappedOptionalTypeSyntax { Data, Data.get() }; + return make(Raw); } ImplicitlyUnwrappedOptionalTypeSyntax SyntaxFactory::makeBlankImplicitlyUnwrappedOptionalType() { - auto Data = ImplicitlyUnwrappedOptionalTypeSyntaxData::makeBlank(); - return ImplicitlyUnwrappedOptionalTypeSyntax { Data, Data.get() }; + return ImplicitlyUnwrappedOptionalTypeSyntax::makeBlank(); } #pragma mark - metatype-type MetatypeTypeSyntax SyntaxFactory::makeMetatypeType(TypeSyntax BaseType, - RC DotToken, - RC TypeToken) { + TokenSyntax DotToken, + TokenSyntax TypeToken) { auto Raw = RawSyntax::make(SyntaxKind::MetatypeType, { BaseType.getRaw(), - DotToken, - TypeToken + DotToken.getRaw(), + TypeToken.getRaw() }, SourcePresence::Present); - auto Data = MetatypeTypeSyntaxData::make(Raw); - return MetatypeTypeSyntax { Data, Data.get() }; + return make(Raw); } MetatypeTypeSyntax SyntaxFactory::makeBlankMetatypeType() { - auto Data = MetatypeTypeSyntaxData::makeBlank(); - return MetatypeTypeSyntax { Data, Data.get() }; + return MetatypeTypeSyntax::makeBlank(); } #pragma mark - function-type FunctionTypeSyntax SyntaxFactory::makeFunctionType( - TypeAttributesSyntax TypeAttributes, RC LeftParen, - FunctionParameterListSyntax ArgumentList, RC RightParen, - RC ThrowsOrRethrows, RC Arrow, + TypeAttributesSyntax TypeAttributes, TokenSyntax LeftParen, + FunctionParameterListSyntax ArgumentList, TokenSyntax RightParen, + TokenSyntax ThrowsOrRethrows, TokenSyntax Arrow, TypeSyntax ReturnType) { auto Raw = RawSyntax::make(SyntaxKind::FunctionType, { TypeAttributes.getRaw(), - LeftParen, + LeftParen.getRaw(), ArgumentList.getRaw(), - RightParen, - ThrowsOrRethrows, - Arrow, + RightParen.getRaw(), + ThrowsOrRethrows.getRaw(), + Arrow.getRaw(), ReturnType.getRaw() }, SourcePresence::Present); - auto Data = FunctionTypeSyntaxData::make(Raw); - return FunctionTypeSyntax { Data, Data.get() }; + return make(Raw); } FunctionTypeSyntax SyntaxFactory::makeBlankFunctionType() { - auto Data = FunctionTypeSyntaxData::makeBlank(); - return FunctionTypeSyntax { Data, Data.get() }; + return FunctionTypeSyntax::makeBlank(); } #pragma mark - function-type-argument FunctionTypeArgumentSyntax SyntaxFactory:: -makeFunctionTypeArgument(RC ExternalParameterName, - RC LocalParameterName, +makeFunctionTypeArgument(TokenSyntax ExternalParameterName, + TokenSyntax LocalParameterName, TypeAttributesSyntax TypeAttributes, - RC InoutKeyword, - RC ColonToken, + TokenSyntax InoutKeyword, + TokenSyntax ColonToken, TypeSyntax ParameterTypeSyntax) { auto Raw = RawSyntax::make(SyntaxKind::FunctionTypeArgument, { - ExternalParameterName, - LocalParameterName, + ExternalParameterName.getRaw(), + LocalParameterName.getRaw(), TypeAttributes.getRaw(), - InoutKeyword, - ColonToken, + InoutKeyword.getRaw(), + ColonToken.getRaw(), ParameterTypeSyntax.getRaw() }, SourcePresence::Present); - auto Data = FunctionTypeArgumentSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } FunctionTypeArgumentSyntax SyntaxFactory:: -makeFunctionTypeArgument(RC LocalParameterName, - RC ColonToken, +makeFunctionTypeArgument(TokenSyntax LocalParameterName, + TokenSyntax ColonToken, swift::syntax::TypeSyntax TypeArgument) { auto Raw = RawSyntax::make(SyntaxKind::FunctionTypeArgument, { - TokenSyntax::missingToken(tok::identifier, ""), - LocalParameterName, + RawTokenSyntax::missingToken(tok::identifier, + ""), + LocalParameterName.getRaw(), RawSyntax::missing(SyntaxKind::TypeAttributes), - TokenSyntax::missingToken(tok::kw_inout, "inout"), - ColonToken, + RawTokenSyntax::missingToken(tok::kw_inout, + "inout"), + ColonToken.getRaw(), TypeArgument.getRaw() }, SourcePresence::Present); - auto Data = FunctionTypeArgumentSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } FunctionTypeArgumentSyntax SyntaxFactory::makeFunctionTypeArgument(TypeSyntax TypeArgument) { auto Raw = RawSyntax::make(SyntaxKind::FunctionTypeArgument, { - TokenSyntax::missingToken(tok::identifier, ""), - TokenSyntax::missingToken(tok::identifier, ""), + RawTokenSyntax::missingToken(tok::identifier, ""), + RawTokenSyntax::missingToken(tok::identifier, ""), RawSyntax::missing(SyntaxKind::TypeAttributes), - TokenSyntax::missingToken(tok::kw_inout, "inout"), - TokenSyntax::missingToken(tok::colon, ":"), + RawTokenSyntax::missingToken(tok::kw_inout, "inout"), + RawTokenSyntax::missingToken(tok::colon, ":"), TypeArgument.getRaw() }, SourcePresence::Present); - auto Data = FunctionTypeArgumentSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } #pragma mark - #pragma mark type-attributes TypeAttributesSyntax SyntaxFactory::makeBlankTypeAttributes() { - auto Data = TypeAttributesSyntaxData::makeBlank(); - return TypeAttributesSyntax { Data, Data.get() }; + return TypeAttributesSyntax::makeBlank(); } TupleTypeElementListSyntax SyntaxFactory::makeBlankTupleTypeElementList() { - auto Data = TupleTypeElementListSyntaxData::makeBlank(); - return TupleTypeElementListSyntax { Data, Data.get() }; + return TupleTypeElementListSyntax::makeBlank(); } #pragma mark - array-type ArrayTypeSyntax -SyntaxFactory::makeArrayType(RC LeftSquareBracket, +SyntaxFactory::makeArrayType(TokenSyntax LeftSquareBracket, TypeSyntax ElementType, - RC RightSquareBracket) { + TokenSyntax RightSquareBracket) { auto Raw = RawSyntax::make(SyntaxKind::ArrayType, { - LeftSquareBracket, + LeftSquareBracket.getRaw(), ElementType.getRaw(), - RightSquareBracket + RightSquareBracket.getRaw() }, SourcePresence::Present); - auto Data = ArrayTypeSyntaxData::make(Raw); - return ArrayTypeSyntax { Data, Data.get() }; + return make(Raw); } ArrayTypeSyntax SyntaxFactory::makeBlankArrayType() { - auto Data = ArrayTypeSyntaxData::makeBlank(); - return ArrayTypeSyntax { Data, Data.get() }; + return ArrayTypeSyntax::makeBlank(); } #pragma mark - dictionary-type DictionaryTypeSyntax -SyntaxFactory::makeDictionaryType(RC LeftSquareBracket, +SyntaxFactory::makeDictionaryType(TokenSyntax LeftSquareBracket, TypeSyntax KeyType, - RC Colon, + TokenSyntax Colon, TypeSyntax ValueType, - RC RightSquareBracket) { + TokenSyntax RightSquareBracket) { auto Raw = RawSyntax::make(SyntaxKind::DictionaryType, { - LeftSquareBracket, + LeftSquareBracket.getRaw(), KeyType.getRaw(), - Colon, + Colon.getRaw(), ValueType.getRaw(), - RightSquareBracket + RightSquareBracket.getRaw() }, SourcePresence::Present); - auto Data = DictionaryTypeSyntaxData::make(Raw); - return DictionaryTypeSyntax { Data, Data.get() }; + return make(Raw); } DictionaryTypeSyntax SyntaxFactory::makeBlankDictionaryType() { - auto Data = DictionaryTypeSyntaxData::makeBlank(); - return DictionaryTypeSyntax { Data, Data.get() }; + return DictionaryTypeSyntax::makeBlank(); } - - diff --git a/lib/Syntax/TypeSyntax.cpp b/lib/Syntax/TypeSyntax.cpp index 05dac82c186..f47d6987d40 100644 --- a/lib/Syntax/TypeSyntax.cpp +++ b/lib/Syntax/TypeSyntax.cpp @@ -20,64 +20,42 @@ using namespace swift::syntax; using llvm::None; using llvm::Optional; -TypeSyntaxData::TypeSyntaxData(RC Raw, const SyntaxData *Parent, - CursorIndex IndexInParent) - : SyntaxData(Raw, Parent, IndexInParent) {} - -TypeSyntax::TypeSyntax(RC Root, const TypeSyntaxData *Data) - : Syntax(Root, Data) {} - #pragma mark - balanced-tokens Data -BalancedTokensSyntaxData::BalancedTokensSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : SyntaxData(Raw, Parent, IndexInParent) { - assert(Raw->Kind == SyntaxKind::BalancedTokens); +void BalancedTokensSyntax::validate() const { + assert(Data->Raw->Kind == SyntaxKind::BalancedTokens); // TODO: Add some checks here that each element of raw syntax // matches the grammar rules in the doc comment of // this class. } -RC -BalancedTokensSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new BalancedTokensSyntaxData { Raw, Parent, IndexInParent } - }; -} - -RC BalancedTokensSyntaxData::makeBlank() { - return make(RawSyntax::make(SyntaxKind::BalancedTokens, {}, - SourcePresence::Present)); +BalancedTokensSyntax BalancedTokensSyntax::makeBlank() { + auto Raw = RawSyntax::make(SyntaxKind::BalancedTokens, {}, + SourcePresence::Present); + return make(Raw); } #pragma mark - balanced-tokens API -BalancedTokensSyntax::BalancedTokensSyntax(RC Root, - const BalancedTokensSyntaxData *Data) - : Syntax(Root, Data) {} - BalancedTokensSyntax -BalancedTokensSyntax::addBalancedToken(RC NewBalancedToken) const { +BalancedTokensSyntax::addBalancedToken(TokenSyntax NewBalancedToken) const { #ifndef NDEBUG - assert(NewBalancedToken->getTokenKind() != tok::l_paren); - assert(NewBalancedToken->getTokenKind() != tok::r_paren); - assert(NewBalancedToken->getTokenKind() != tok::l_square); - assert(NewBalancedToken->getTokenKind() != tok::r_square); - assert(NewBalancedToken->getTokenKind() != tok::l_brace); - assert(NewBalancedToken->getTokenKind() != tok::r_brace); - auto IsIdentifier = NewBalancedToken->getTokenKind() == tok::identifier; - auto IsKeyword = NewBalancedToken->isKeyword(); - auto IsLiteral = NewBalancedToken->isLiteral(); - auto IsOperator = NewBalancedToken->isOperator(); - auto IsPunctuation = NewBalancedToken->isPunctuation(); + assert(NewBalancedToken.getTokenKind() != tok::l_paren); + assert(NewBalancedToken.getTokenKind() != tok::r_paren); + assert(NewBalancedToken.getTokenKind() != tok::l_square); + assert(NewBalancedToken.getTokenKind() != tok::r_square); + assert(NewBalancedToken.getTokenKind() != tok::l_brace); + assert(NewBalancedToken.getTokenKind() != tok::r_brace); + auto IsIdentifier = NewBalancedToken.getTokenKind() == tok::identifier; + auto IsKeyword = NewBalancedToken.isKeyword(); + auto IsLiteral = NewBalancedToken.isLiteral(); + auto IsOperator = NewBalancedToken.isOperator(); + auto IsPunctuation = NewBalancedToken.isPunctuation(); assert(IsIdentifier || IsKeyword || IsLiteral || IsOperator || IsPunctuation); #endif auto Layout = getRaw()->Layout; - Layout.push_back(NewBalancedToken); + Layout.push_back(NewBalancedToken.getRaw()); auto NewRaw = RawSyntax::make(SyntaxKind::BalancedTokens, Layout, SourcePresence::Present); @@ -86,10 +64,8 @@ BalancedTokensSyntax::addBalancedToken(RC NewBalancedToken) const { #pragma mark - type-attribute Data -TypeAttributeSyntaxData::TypeAttributeSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : SyntaxData(Raw, Parent, IndexInParent) { +void TypeAttributeSyntax::validate() const { + auto Raw = Data->Raw; assert(Raw->Kind == SyntaxKind::TypeAttribute); assert(Raw->Layout.size() == 5); syntax_assert_child_token_text(Raw, @@ -109,52 +85,39 @@ TypeAttributeSyntaxData::TypeAttributeSyntaxData(RC Raw, ")"); } -RC -TypeAttributeSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new TypeAttributeSyntaxData { Raw, Parent, IndexInParent } - }; -} - -RC TypeAttributeSyntaxData::makeBlank() { - auto Raw = RawSyntax::make(SyntaxKind::TypeAttribute, - { - TokenSyntax::missingToken(tok::at_sign, "@"), - TokenSyntax::missingToken(tok::identifier, ""), - TokenSyntax::missingToken(tok::l_paren, "("), - RawSyntax::missing(SyntaxKind::BalancedTokens), - TokenSyntax::missingToken(tok::r_paren, ")"), - }, - SourcePresence::Present); - return make(Raw); -} - #pragma mark - type-attribute API -TypeAttributeSyntax::TypeAttributeSyntax(RC Root, - const TypeAttributeSyntaxData *Data) - : Syntax(Root, Data) {} +TypeAttributeSyntax TypeAttributeSyntax::makeBlank() { + auto Raw = RawSyntax::make(SyntaxKind::TypeAttribute, + { + RawTokenSyntax::missingToken(tok::at_sign, "@"), + RawTokenSyntax::missingToken(tok::identifier, ""), + RawTokenSyntax::missingToken(tok::l_paren, "("), + RawSyntax::missing(SyntaxKind::BalancedTokens), + RawTokenSyntax::missingToken(tok::r_paren, ")"), + }, + SourcePresence::Present); + return make(Raw); +} TypeAttributeSyntax -TypeAttributeSyntax::withAtSignToken(RC NewAtSignToken) const { +TypeAttributeSyntax::withAtSignToken(TokenSyntax NewAtSignToken) const { syntax_assert_token_is(NewAtSignToken, tok::at_sign, "@"); - return Data->replaceChild(NewAtSignToken, + return Data->replaceChild(NewAtSignToken.getRaw(), Cursor::AtSignToken); } TypeAttributeSyntax -TypeAttributeSyntax::withIdentifier(RC NewIdentifier) const { - assert(NewIdentifier->getTokenKind() == tok::identifier); - return Data->replaceChild(NewIdentifier, +TypeAttributeSyntax::withIdentifier(TokenSyntax NewIdentifier) const { + assert(NewIdentifier.getTokenKind() == tok::identifier); + return Data->replaceChild(NewIdentifier.getRaw(), Cursor::Identifier); }; TypeAttributeSyntax TypeAttributeSyntax:: -withLeftParenToken(RC NewLeftParenToken) const { - assert(NewLeftParenToken->getTokenKind() == tok::l_paren); - return Data->replaceChild(NewLeftParenToken, +withLeftParenToken(TokenSyntax NewLeftParenToken) const { + assert(NewLeftParenToken.getTokenKind() == tok::l_paren); + return Data->replaceChild(NewLeftParenToken.getRaw(), Cursor::LeftParenToken); }; @@ -165,56 +128,16 @@ withBalancedTokens(BalancedTokensSyntax NewBalancedTokens) const { } TypeAttributeSyntax TypeAttributeSyntax:: -withRightParenToken(RC NewRightParenToken) const { - assert(NewRightParenToken->getTokenKind() == tok::r_paren); - return Data->replaceChild(NewRightParenToken, +withRightParenToken(TokenSyntax NewRightParenToken) const { + assert(NewRightParenToken.getTokenKind() == tok::r_paren); + return Data->replaceChild(NewRightParenToken.getRaw(), Cursor::RightParenToken); }; -#pragma mark - type-attributes Data +#pragma mark - type-identifier API -TypeAttributesSyntaxData::TypeAttributesSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : SyntaxData(Raw, Parent, IndexInParent) { - // TODO: kind assertions -} - -RC -TypeAttributesSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new TypeAttributesSyntaxData { Raw, Parent, IndexInParent } - }; -} - -RC TypeAttributesSyntaxData::makeBlank() { - return make(RawSyntax::make(SyntaxKind::TypeAttributes, {}, - SourcePresence::Present)); -} - -#pragma mark - type-attributes API - -TypeAttributesSyntax:: -TypeAttributesSyntax(RC Root, const TypeAttributesSyntaxData *Data) - : Syntax(Root, Data) {} - -TypeAttributesSyntax TypeAttributesSyntax:: -addTypeAttribute(TypeAttributeSyntax NewTypeAttribute) const { - auto Layout = getRaw()->Layout; - Layout.push_back(NewTypeAttribute.getRaw()); - auto NewRaw = RawSyntax::make(SyntaxKind::TypeAttributes, Layout, - SourcePresence::Present); - return Data->replaceSelf(NewRaw); -} - -#pragma mark - type-identifier Data - -TypeIdentifierSyntaxData::TypeIdentifierSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : TypeSyntaxData(Raw, Parent, IndexInParent) { +void TypeIdentifierSyntax::validate() const { + auto Raw = Data->Raw; assert(Raw->Kind == SyntaxKind::TypeIdentifier); assert(Raw->Layout.size() == 4); syntax_assert_child_token(Raw, TypeIdentifierSyntax::Cursor::Identifier, @@ -229,34 +152,18 @@ TypeIdentifierSyntaxData::TypeIdentifierSyntaxData(RC Raw, SyntaxKind::TypeIdentifier); } -RC -TypeIdentifierSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new TypeIdentifierSyntaxData { Raw, Parent, IndexInParent } - }; -} - -RC -TypeIdentifierSyntaxData::makeBlank() { - return make(RawSyntax::make( +TypeIdentifierSyntax TypeIdentifierSyntax::makeBlank() { + return make(RawSyntax::make( SyntaxKind::TypeIdentifier, { - TokenSyntax::missingToken(tok::identifier, ""), + RawTokenSyntax::missingToken(tok::identifier, ""), RawSyntax::missing(SyntaxKind::GenericArgumentClause), - TokenSyntax::missingToken(tok::period, "."), + RawTokenSyntax::missingToken(tok::period, "."), RawSyntax::missing(SyntaxKind::TypeIdentifier), }, SourcePresence::Present)); } -#pragma mark - type-identifier API - -TypeIdentifierSyntax::TypeIdentifierSyntax(RC Root, - const TypeIdentifierSyntaxData *Data) - : TypeSyntax(Root, Data) {} - TypeIdentifierSyntax TypeIdentifierSyntax::addChildType(TypeIdentifierSyntax ChildType) const { auto MaybeChild = getRaw()->getChild(Cursor::ChildTypeIdentifier); @@ -264,7 +171,7 @@ TypeIdentifierSyntax::addChildType(TypeIdentifierSyntax ChildType) const { if (MaybeChild->isMissing()) { auto NewRaw = getRaw()->replaceChild(Cursor::DotToken, - SyntaxFactory::makeDotToken({}, {})) + SyntaxFactory::makeDotToken({}, {}).getRaw()) ->replaceChild(Cursor::ChildTypeIdentifier, ChildType.getRaw()); return Data->replaceSelf(NewRaw); @@ -278,26 +185,23 @@ TypeIdentifierSyntax::addChildType(TypeIdentifierSyntax ChildType) const { } TypeIdentifierSyntax -TypeIdentifierSyntax::withIdentifier(RC NewIdentifier) const { - assert(NewIdentifier->getTokenKind() == tok::identifier); - auto NewRaw = getRaw()->replaceChild(Cursor::Identifier, - NewIdentifier); - return Data->replaceSelf(NewRaw); +TypeIdentifierSyntax::withIdentifier(TokenSyntax NewIdentifier) const { + assert(NewIdentifier.getTokenKind() == tok::identifier); + return Data->replaceChild(NewIdentifier.getRaw(), + Cursor::Identifier); } TypeIdentifierSyntax -TypeIdentifierSyntax::withDotToken(RC NewDotToken) const { +TypeIdentifierSyntax::withDotToken(TokenSyntax NewDotToken) const { syntax_assert_token_is(NewDotToken, tok::period, "."); - auto NewRaw = getRaw()->replaceChild(Cursor::DotToken, NewDotToken); - return Data->replaceSelf(NewRaw); + return Data->replaceChild(NewDotToken.getRaw(), + Cursor::DotToken); } -#pragma mark - tuple-type Data +#pragma mark - tuple-type API -TupleTypeSyntaxData::TupleTypeSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : TypeSyntaxData(Raw, Parent, IndexInParent) { +void TupleTypeSyntax::validate() const { + auto Raw = Data->Raw; assert(Raw->Kind == SyntaxKind::TupleType); assert(Raw->Layout.size() == 3); syntax_assert_child_token_text(Raw, TupleTypeSyntax::Cursor::LeftParenToken, @@ -310,37 +214,23 @@ TupleTypeSyntaxData::TupleTypeSyntaxData(RC Raw, ")"); } -RC -TupleTypeSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new TupleTypeSyntaxData { Raw, Parent, IndexInParent } - }; -} - -RC -TupleTypeSyntaxData::makeBlank() { - return make( +TupleTypeSyntax +TupleTypeSyntax::makeBlank() { + return make( RawSyntax::make(SyntaxKind::TupleType, { - TokenSyntax::missingToken(tok::l_paren, "("), + RawTokenSyntax::missingToken(tok::l_paren, "("), RawSyntax::missing(SyntaxKind::TupleTypeElementList), - TokenSyntax::missingToken(tok::r_paren, ")"), + RawTokenSyntax::missingToken(tok::r_paren, ")"), }, SourcePresence::Present)); } -#pragma mark - tuple-type API - -TupleTypeSyntax::TupleTypeSyntax(RC Root, - const TupleTypeSyntaxData *Data) - : TypeSyntax(Root, Data) {} - TupleTypeSyntax -TupleTypeSyntax::withLeftParen(RC NewLeftParen) const { +TupleTypeSyntax::withLeftParen(TokenSyntax NewLeftParen) const { syntax_assert_token_is(NewLeftParen, tok::l_paren, "("); - auto NewRaw = getRaw()->replaceChild(Cursor::LeftParenToken, NewLeftParen); + auto NewRaw = getRaw()->replaceChild(Cursor::LeftParenToken, + NewLeftParen.getRaw()); return Data->replaceSelf(NewRaw); } @@ -352,10 +242,10 @@ withTypeElementList(TupleTypeElementListSyntax NewTypeElementList) const { } TupleTypeSyntax TupleTypeSyntax:: -withRightParen(RC NewRightParen) const { +withRightParen(TokenSyntax NewRightParen) const { syntax_assert_token_is(NewRightParen, tok::r_paren, ")"); - auto NewRaw = getRaw()->replaceChild(Cursor::RightParenToken, NewRightParen); - return Data->replaceSelf(NewRaw); + return Data->replaceChild(NewRightParen.getRaw(), + Cursor::RightParenToken); } #pragma mark - tuple-type Builder @@ -371,14 +261,14 @@ addElementTypeSyntax(TupleTypeElementSyntax ElementTypeSyntax) { } TupleTypeSyntaxBuilder & -TupleTypeSyntaxBuilder::useLeftParen(RC LeftParen) { - LeftParenToken = LeftParen; +TupleTypeSyntaxBuilder::useLeftParen(TokenSyntax LeftParen) { + LeftParenToken = LeftParen.getRaw(); return *this; } TupleTypeSyntaxBuilder & -TupleTypeSyntaxBuilder::useRightParen(RC RightParen) { - RightParenToken = RightParen; +TupleTypeSyntaxBuilder::useRightParen(TokenSyntax RightParen) { + RightParenToken = RightParen.getRaw(); return *this; } @@ -393,17 +283,13 @@ TupleTypeSyntax TupleTypeSyntaxBuilder::build() const { RightParenToken, }, SourcePresence::Present); - auto Data = TupleTypeSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } -#pragma mark - tuple-type-element Data +#pragma mark - tuple-type-element API -TupleTypeElementSyntaxData:: -TupleTypeElementSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : SyntaxData(Raw, Parent, IndexInParent) { +void TupleTypeElementSyntax::validate() const { + auto Raw = Data->Raw; assert(Raw->Kind == SyntaxKind::TupleTypeElement); assert(Raw->Layout.size() == 6); syntax_assert_child_token(Raw, TupleTypeElementSyntax::Cursor::Label, @@ -423,77 +309,61 @@ TupleTypeElementSyntaxData(RC Raw, assert(Raw->getChild(TupleTypeElementSyntax::Cursor::Type)->isType()); } -RC -TupleTypeElementSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new TupleTypeElementSyntaxData { Raw, Parent, IndexInParent } - }; -} - -RC -TupleTypeElementSyntaxData::makeBlank() { - return make( +TupleTypeElementSyntax TupleTypeElementSyntax::makeBlank() { + return make( RawSyntax::make(SyntaxKind::TupleTypeElement, { - TokenSyntax::missingToken(tok::identifier, ""), - TokenSyntax::missingToken(tok::colon, ":"), + RawTokenSyntax::missingToken(tok::identifier, ""), + RawTokenSyntax::missingToken(tok::colon, ":"), RawSyntax::missing(SyntaxKind::TypeAttributes), - TokenSyntax::missingToken(tok::kw_inout, "inout"), + RawTokenSyntax::missingToken(tok::kw_inout, "inout"), RawSyntax::missing(SyntaxKind::MissingType), - TokenSyntax::missingToken(tok::comma, ","), + RawTokenSyntax::missingToken(tok::comma, ","), }, SourcePresence::Present)); } -#pragma mark - tuple-type-element API -TupleTypeElementSyntax:: -TupleTypeElementSyntax(RC Root, - const TupleTypeElementSyntaxData *Data) - : Syntax(Root, Data) {} - -RC +TokenSyntax TupleTypeElementSyntax::getLabel() const { - auto Label = cast(getRaw()->getChild(Cursor::Label)); - assert(Label->getTokenKind() == tok::identifier); - return Label; + TokenSyntax Child = { Root, Data->getChild(Cursor::Label).get() }; + assert(Child.getTokenKind() == tok::identifier); + return Child; } TupleTypeElementSyntax -TupleTypeElementSyntax::withLabel(RC NewLabel) const { - assert(NewLabel->getTokenKind() == tok::identifier); - auto NewRaw = getRaw()->replaceChild(Cursor::Label, NewLabel); - return Data->replaceSelf(NewRaw); +TupleTypeElementSyntax::withLabel(TokenSyntax NewLabel) const { + assert(NewLabel.getTokenKind() == tok::identifier); + return Data->replaceChild(NewLabel.getRaw(), + Cursor::Label); } -RC +TokenSyntax TupleTypeElementSyntax::getColonToken() const { - auto ColonToken = cast(getRaw()->getChild(Cursor::ColonToken)); + TokenSyntax ColonToken = { Root, Data->getChild(Cursor::ColonToken).get() }; syntax_assert_token_is(ColonToken, tok::colon, ":"); return ColonToken; } TupleTypeElementSyntax -TupleTypeElementSyntax::withColonToken(RC NewColonToken) const { - syntax_assert_token_is(NewColonToken, tok::colon, ":") - auto NewRaw = getRaw()->replaceChild(Cursor::ColonToken, NewColonToken); - return Data->replaceSelf(NewRaw); +TupleTypeElementSyntax::withColonToken(TokenSyntax NewColonToken) const { + syntax_assert_token_is(NewColonToken, tok::colon, ":"); + return Data->replaceChild(NewColonToken.getRaw(), + Cursor::ColonToken); } -RC +TokenSyntax TupleTypeElementSyntax::getCommaToken() const { - auto CommaToken = cast(getRaw()->getChild(Cursor::CommaToken)); + TokenSyntax CommaToken = { Root, Data->getChild(Cursor::CommaToken).get() }; syntax_assert_token_is(CommaToken, tok::comma, ","); return CommaToken; } TupleTypeElementSyntax -TupleTypeElementSyntax::withCommaToken(RC NewCommaToken) const { - syntax_assert_token_is(NewCommaToken, tok::comma, ",") - auto NewRaw = getRaw()->replaceChild(Cursor::CommaToken, NewCommaToken); - return Data->replaceSelf(NewRaw); +TupleTypeElementSyntax::withCommaToken(TokenSyntax NewCommaToken) const { + syntax_assert_token_is(NewCommaToken, tok::comma, ","); + return Data->replaceChild(NewCommaToken.getRaw(), + Cursor::CommaToken); } TupleTypeElementSyntax TupleTypeElementSyntax:: @@ -504,24 +374,22 @@ withTypeAttributes(TypeAttributesSyntax NewTypeAttributes) const { } TupleTypeElementSyntax TupleTypeElementSyntax:: -withInoutToken(RC NewInoutToken) const { +withInoutToken(TokenSyntax NewInoutToken) const { syntax_assert_token_is(NewInoutToken, tok::kw_inout, "inout"); - auto NewRaw = getRaw()->replaceChild(Cursor::InoutToken, NewInoutToken); - return Data->replaceSelf(NewRaw); + return Data->replaceChild(NewInoutToken.getRaw(), + Cursor::InoutToken); } TupleTypeElementSyntax TupleTypeElementSyntax::withTypeSyntax(TypeSyntax NewTypeSyntax) const { - auto NewRaw = getRaw()->replaceChild(Cursor::Type, NewTypeSyntax.getRaw()); - return Data->replaceSelf(NewRaw); + return Data->replaceChild(NewTypeSyntax.getRaw(), + Cursor::Type); } -#pragma mark - metatype-type Data +#pragma mark - metatype-type API -MetatypeTypeSyntaxData::MetatypeTypeSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : TypeSyntaxData(Raw, Parent, IndexInParent) { +void MetatypeTypeSyntax::validate() const { + auto Raw = Data->Raw; assert(Raw->Kind == SyntaxKind::MetatypeType); assert(Raw->Layout.size() == 3); assert(Raw->getChild(MetatypeTypeSyntax::Cursor::BaseType)->isType()); @@ -531,31 +399,18 @@ MetatypeTypeSyntaxData::MetatypeTypeSyntaxData(RC Raw, tok::identifier); } -RC -MetatypeTypeSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new MetatypeTypeSyntaxData { Raw, Parent, IndexInParent } - }; +MetatypeTypeSyntax MetatypeTypeSyntax::makeBlank() { + auto Raw = RawSyntax::make(SyntaxKind::MetatypeType, + { + RawSyntax::missing(SyntaxKind::MissingType), + RawTokenSyntax::missingToken(tok::period, "."), + RawTokenSyntax::missingToken(tok::identifier, + ""), + }, + SourcePresence::Present); + return make(Raw); } -RC MetatypeTypeSyntaxData::makeBlank() { - return make(RawSyntax::make(SyntaxKind::MetatypeType, - { - RawSyntax::missing(SyntaxKind::MissingType), - TokenSyntax::missingToken(tok::period, "."), - TokenSyntax::missingToken(tok::identifier, ""), - }, - SourcePresence::Present)); -} - -#pragma mark - metatype-type API - -MetatypeTypeSyntax::MetatypeTypeSyntax(RC Root, - const MetatypeTypeSyntaxData *Data) - : TypeSyntax(Root, Data) {} - MetatypeTypeSyntax MetatypeTypeSyntax::withBaseTypeSyntax(TypeSyntax NewBaseTypeSyntax) const { auto NewRaw = getRaw()->replaceChild(Cursor::BaseType, @@ -564,27 +419,25 @@ MetatypeTypeSyntax::withBaseTypeSyntax(TypeSyntax NewBaseTypeSyntax) const { } MetatypeTypeSyntax -MetatypeTypeSyntax::withDotToken(RC NewDotToken) const { +MetatypeTypeSyntax::withDotToken(TokenSyntax NewDotToken) const { syntax_assert_token_is(NewDotToken, tok::period, "."); - auto NewRaw = getRaw()->replaceChild(Cursor::DotToken, NewDotToken); - return Data->replaceSelf(NewRaw); + return Data->replaceChild(NewDotToken.getRaw(), + Cursor::DotToken); } MetatypeTypeSyntax -MetatypeTypeSyntax::withTypeToken(RC NewTypeToken) const { - assert(NewTypeToken->getTokenKind() == tok::identifier); - assert(NewTypeToken->getText() == "Type" || - NewTypeToken->getText() == "Protocol"); - auto NewRaw = getRaw()->replaceChild(Cursor::TypeToken, NewTypeToken); - return Data->replaceSelf(NewRaw); +MetatypeTypeSyntax::withTypeToken(TokenSyntax NewTypeToken) const { + assert(NewTypeToken.getTokenKind() == tok::identifier); + assert(NewTypeToken.getText() == "Type" || + NewTypeToken.getText() == "Protocol"); + return Data->replaceChild(NewTypeToken.getRaw(), + Cursor::TypeToken); } -#pragma mark - optional-type Data +#pragma mark - optional-type API -OptionalTypeSyntaxData::OptionalTypeSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : TypeSyntaxData(Raw, Parent, IndexInParent) { +void OptionalTypeSyntax::validate() const { + auto Raw = Data->Raw; assert(Raw->Kind == SyntaxKind::OptionalType); assert(Raw->Layout.size() == 2); assert(Raw->getChild(OptionalTypeSyntax::Cursor::BaseType)->isType()); @@ -592,30 +445,15 @@ OptionalTypeSyntaxData::OptionalTypeSyntaxData(RC Raw, tok::question_postfix, "?"); } -RC -OptionalTypeSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new OptionalTypeSyntaxData { Raw, Parent, IndexInParent } - }; -} - -RC OptionalTypeSyntaxData::makeBlank() { - return make(RawSyntax::make(SyntaxKind::OptionalType, +OptionalTypeSyntax OptionalTypeSyntax::makeBlank() { + return make(RawSyntax::make(SyntaxKind::OptionalType, { RawSyntax::missing(SyntaxKind::MissingType), - TokenSyntax::missingToken(tok::question_postfix, "?"), + RawTokenSyntax::missingToken(tok::question_postfix, "?"), }, SourcePresence::Present)); } -#pragma mark - optional-type API - -OptionalTypeSyntax::OptionalTypeSyntax(RC Root, - const OptionalTypeSyntaxData *Data) - : TypeSyntax(Root, Data) {} - OptionalTypeSyntax OptionalTypeSyntax::withBaseTypeSyntax(TypeSyntax NewTypeSyntax) const { auto NewRaw = getRaw()->replaceChild(Cursor::BaseType, NewTypeSyntax.getRaw()); @@ -623,19 +461,16 @@ OptionalTypeSyntax::withBaseTypeSyntax(TypeSyntax NewTypeSyntax) const { } OptionalTypeSyntax -OptionalTypeSyntax::withQuestionToken(RC NewQuestionToken) const { +OptionalTypeSyntax::withQuestionToken(TokenSyntax NewQuestionToken) const { syntax_assert_token_is(NewQuestionToken, tok::question_postfix, "?"); - auto NewRaw = getRaw()->replaceChild(Cursor::QuestionToken, NewQuestionToken); - return Data->replaceSelf(NewRaw); + return Data->replaceChild(NewQuestionToken.getRaw(), + Cursor::QuestionToken); } -#pragma mark - implicitly-unwrapped-optional-type Data +#pragma mark - implicitly-unwrapped-optional-type API -ImplicitlyUnwrappedOptionalTypeSyntaxData:: -ImplicitlyUnwrappedOptionalTypeSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : TypeSyntaxData(Raw, Parent, IndexInParent) { +void ImplicitlyUnwrappedOptionalTypeSyntax::validate() const { + auto Raw = Data->Raw; assert(Raw->Kind == SyntaxKind::ImplicitlyUnwrappedOptionalType); assert(Raw->Layout.size() == 2); assert(Raw->getChild(ImplicitlyUnwrappedOptionalTypeSyntax::Cursor::Type) @@ -645,32 +480,18 @@ ImplicitlyUnwrappedOptionalTypeSyntaxData(RC Raw, tok::exclaim_postfix, "!"); } -RC -ImplicitlyUnwrappedOptionalTypeSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new ImplicitlyUnwrappedOptionalTypeSyntaxData { Raw, Parent, IndexInParent } - }; +ImplicitlyUnwrappedOptionalTypeSyntax +ImplicitlyUnwrappedOptionalTypeSyntax::makeBlank() { + auto Raw = RawSyntax::make( + SyntaxKind::ImplicitlyUnwrappedOptionalType, + { + RawSyntax::missing(SyntaxKind::MissingType), + RawTokenSyntax::missingToken(tok::exclaim_postfix, "!"), + }, + SourcePresence::Present); + return make(Raw); } -RC -ImplicitlyUnwrappedOptionalTypeSyntaxData::makeBlank() { - return make(RawSyntax::make(SyntaxKind::ImplicitlyUnwrappedOptionalType, - { - RawSyntax::missing(SyntaxKind::MissingType), - TokenSyntax::missingToken(tok::exclaim_postfix, "!"), - }, - SourcePresence::Present)); -} - -#pragma mark - implicitly-unwrapped-optional-type API - -ImplicitlyUnwrappedOptionalTypeSyntax:: -ImplicitlyUnwrappedOptionalTypeSyntax(RC Root, - const ImplicitlyUnwrappedOptionalTypeSyntaxData *Data) - : TypeSyntax(Root, Data) {} - ImplicitlyUnwrappedOptionalTypeSyntax ImplicitlyUnwrappedOptionalTypeSyntax:: withBaseTypeSyntax(TypeSyntax NewTypeSyntax) const { auto NewRaw = getRaw()->replaceChild(Cursor::Type, NewTypeSyntax.getRaw()); @@ -678,18 +499,16 @@ withBaseTypeSyntax(TypeSyntax NewTypeSyntax) const { } ImplicitlyUnwrappedOptionalTypeSyntax ImplicitlyUnwrappedOptionalTypeSyntax:: -withExclaimToken(RC NewExclaimToken) const { +withExclaimToken(TokenSyntax NewExclaimToken) const { syntax_assert_token_is(NewExclaimToken, tok::exclaim_postfix, "!"); - auto NewRaw = getRaw()->replaceChild(Cursor::ExclaimToken, NewExclaimToken); - return Data->replaceSelf(NewRaw); + return Data->replaceChild( + NewExclaimToken.getRaw(), Cursor::ExclaimToken); } -#pragma mark - array-type Data +#pragma mark - array-type API -ArrayTypeSyntaxData::ArrayTypeSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : TypeSyntaxData(Raw, Parent, IndexInParent) { +void ArrayTypeSyntax::validate() const { + auto Raw = Data->Raw; assert(Raw->Kind == SyntaxKind::ArrayType); assert(Raw->Layout.size() == 3); syntax_assert_child_token_text(Raw, @@ -701,36 +520,22 @@ ArrayTypeSyntaxData::ArrayTypeSyntaxData(RC Raw, tok::r_square, "]"); } -RC ArrayTypeSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new ArrayTypeSyntaxData { Raw, Parent, IndexInParent } - }; +ArrayTypeSyntax ArrayTypeSyntax::makeBlank() { + auto Raw = RawSyntax::make(SyntaxKind::ArrayType, + { + RawTokenSyntax::missingToken(tok::l_square, "["), + RawSyntax::missing(SyntaxKind::MissingType), + RawTokenSyntax::missingToken(tok::r_square, "]"), + }, + SourcePresence::Present); + return make(Raw); } -RC ArrayTypeSyntaxData::makeBlank() { - return make(RawSyntax::make(SyntaxKind::ArrayType, - { - TokenSyntax::missingToken(tok::l_square, "["), - RawSyntax::missing(SyntaxKind::MissingType), - TokenSyntax::missingToken(tok::r_square, "]"), - }, - SourcePresence::Present)); -} - -#pragma mark - array-type API - -ArrayTypeSyntax::ArrayTypeSyntax(RC Root, - const ArrayTypeSyntaxData *Data) - : TypeSyntax(Root, Data) {} - ArrayTypeSyntax ArrayTypeSyntax:: -withLeftSquareBracketToken(RC NewLeftSquareBracketToken) const { +withLeftSquareBracketToken(TokenSyntax NewLeftSquareBracketToken) const { syntax_assert_token_is(NewLeftSquareBracketToken, tok::l_square, "["); - auto NewRaw = getRaw()->replaceChild(Cursor::LeftSquareBracketToken, - NewLeftSquareBracketToken); - return Data->replaceSelf(NewRaw); + return Data->replaceChild(NewLeftSquareBracketToken.getRaw(), + Cursor::LeftSquareBracketToken); } ArrayTypeSyntax ArrayTypeSyntax::withType(TypeSyntax NewType) const { @@ -739,19 +544,17 @@ ArrayTypeSyntax ArrayTypeSyntax::withType(TypeSyntax NewType) const { } ArrayTypeSyntax ArrayTypeSyntax:: -withRightSquareBracketToken(RC NewRightSquareBracketToken) const { +withRightSquareBracketToken(TokenSyntax NewRightSquareBracketToken) const { syntax_assert_token_is(NewRightSquareBracketToken, tok::r_square, "]"); - auto NewRaw = getRaw()->replaceChild(Cursor::RightSquareBracketToken, - NewRightSquareBracketToken); - return Data->replaceSelf(NewRaw); + return Data->replaceChild( + NewRightSquareBracketToken.getRaw(), + Cursor::RightSquareBracketToken); } -#pragma mark - dictionary-type Data +#pragma mark - dictionary-type API -DictionaryTypeSyntaxData::DictionaryTypeSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : TypeSyntaxData(Raw, Parent, IndexInParent) { +void DictionaryTypeSyntax::validate() const { + auto Raw = Data->Raw; assert(Raw->Kind == SyntaxKind::DictionaryType); assert(Raw->Layout.size() == 5); @@ -767,112 +570,72 @@ DictionaryTypeSyntaxData::DictionaryTypeSyntaxData(RC Raw, tok::r_square, "]"); } -RC -DictionaryTypeSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new DictionaryTypeSyntaxData { Raw, Parent, IndexInParent } - }; +DictionaryTypeSyntax DictionaryTypeSyntax::makeBlank() { + auto Raw = RawSyntax::make(SyntaxKind::DictionaryType, + { + RawTokenSyntax::missingToken(tok::l_square, "["), + RawSyntax::missing(SyntaxKind::MissingType), + RawTokenSyntax::missingToken(tok::colon, ":"), + RawSyntax::missing(SyntaxKind::MissingType), + RawTokenSyntax::missingToken(tok::r_square, "]"), + }, + SourcePresence::Present); + return make(Raw); } -RC -DictionaryTypeSyntaxData::makeBlank() { - return make(RawSyntax::make(SyntaxKind::DictionaryType, - { - TokenSyntax::missingToken(tok::l_square, "["), - RawSyntax::missing(SyntaxKind::MissingType), - TokenSyntax::missingToken(tok::colon, ":"), - RawSyntax::missing(SyntaxKind::MissingType), - TokenSyntax::missingToken(tok::r_square, "]"), - }, - SourcePresence::Present)); -} - -#pragma mark - dictionary-type API - -DictionaryTypeSyntax::DictionaryTypeSyntax(RC Root, - const DictionaryTypeSyntaxData *Data) - : TypeSyntax(Root, Data) {} - DictionaryTypeSyntax DictionaryTypeSyntax:: -withLeftSquareBracketToken(RC NewLeftSquareBracketToken) const { +withLeftSquareBracketToken(TokenSyntax NewLeftSquareBracketToken) const { syntax_assert_token_is(NewLeftSquareBracketToken, tok::l_square, "["); - auto NewRaw = getRaw()->replaceChild(Cursor::LeftSquareBracketToken, - NewLeftSquareBracketToken); - return Data->replaceSelf(NewRaw); + return Data->replaceChild( + NewLeftSquareBracketToken.getRaw(), Cursor::LeftSquareBracketToken); } DictionaryTypeSyntax DictionaryTypeSyntax::withKeyTypeSyntax(TypeSyntax NewTypeSyntax) const { - auto NewRaw = getRaw()->replaceChild(Cursor::KeyType, NewTypeSyntax.getRaw()); - return Data->replaceSelf(NewRaw); + return Data->replaceChild(NewTypeSyntax.getRaw(), + Cursor::KeyType); } DictionaryTypeSyntax -DictionaryTypeSyntax::withColon(RC NewColonToken) const { +DictionaryTypeSyntax::withColon(TokenSyntax NewColonToken) const { syntax_assert_token_is(NewColonToken, tok::colon, ":"); - auto NewRaw = getRaw()->replaceChild(Cursor::ColonToken, NewColonToken); - return Data->replaceSelf(NewRaw); + return Data->replaceChild(NewColonToken.getRaw(), + Cursor::ColonToken); } DictionaryTypeSyntax DictionaryTypeSyntax::withValueTypeSyntax(TypeSyntax NewTypeSyntax) const { - auto NewRaw = getRaw()->replaceChild(Cursor::ValueType, - NewTypeSyntax.getRaw()); - return Data->replaceSelf(NewRaw); + return Data->replaceChild(NewTypeSyntax.getRaw(), + Cursor::ValueType); } DictionaryTypeSyntax DictionaryTypeSyntax:: -withRightSquareBracketToken(RC NewRightSquareBracketToken) const { +withRightSquareBracketToken(TokenSyntax NewRightSquareBracketToken) const { syntax_assert_token_is(NewRightSquareBracketToken, tok::r_square, "]"); - auto NewRaw = getRaw()->replaceChild(Cursor::RightSquareBracketToken, - NewRightSquareBracketToken); - return Data->replaceSelf(NewRaw); -} - -#pragma mark - function-type-argument Data - -FunctionTypeArgumentSyntaxData:: -FunctionTypeArgumentSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : SyntaxData(Raw, Parent, IndexInParent) {} - -RC -FunctionTypeArgumentSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new FunctionTypeArgumentSyntaxData { Raw, Parent, IndexInParent } - }; -} - -RC -FunctionTypeArgumentSyntaxData::makeBlank() { - auto Raw = RawSyntax::make(SyntaxKind::FunctionTypeArgument, - { - TokenSyntax::missingToken(tok::identifier, ""), - TokenSyntax::missingToken(tok::identifier, ""), - TokenSyntax::missingToken(tok::colon, ","), - }, - SourcePresence::Present); - return make(Raw); + return Data->replaceChild( + NewRightSquareBracketToken.getRaw(), + Cursor::RightSquareBracketToken); } #pragma mark - function-type-argument API -FunctionTypeArgumentSyntax:: -FunctionTypeArgumentSyntax(RC Root, - const FunctionTypeArgumentSyntaxData *Data) - : Syntax(Root, Data) {} +void FunctionTypeArgumentSyntax::validate() const {} -#pragma mark - function-type Data +FunctionTypeArgumentSyntax FunctionTypeArgumentSyntax::makeBlank() { + auto Raw = RawSyntax::make(SyntaxKind::FunctionTypeArgument, + { + RawTokenSyntax::missingToken(tok::identifier, ""), + RawTokenSyntax::missingToken(tok::identifier, ""), + RawTokenSyntax::missingToken(tok::colon, ","), + }, + SourcePresence::Present); + return make(Raw); +} -FunctionTypeSyntaxData::FunctionTypeSyntaxData(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) - : TypeSyntaxData(Raw, Parent, IndexInParent) { +#pragma mark - function-type API + +void FunctionTypeSyntax::validate() const { + auto Raw = Data->Raw; assert(Raw->Kind == SyntaxKind::FunctionType); syntax_assert_child_kind(Raw, FunctionTypeSyntax::Cursor::TypeAttributes, SyntaxKind::TypeAttributes); @@ -886,7 +649,7 @@ FunctionTypeSyntaxData::FunctionTypeSyntaxData(RC Raw, tok::r_paren, ")"); #ifndef NDEBUG auto ThrowsOrRethrows = - cast( + cast( Raw->getChild(FunctionTypeSyntax::Cursor::ThrowsOrRethrows)); assert(ThrowsOrRethrows->is(tok::kw_throws, "throws") || ThrowsOrRethrows->is(tok::kw_rethrows, "rethrows")); @@ -896,35 +659,20 @@ FunctionTypeSyntaxData::FunctionTypeSyntaxData(RC Raw, assert(Raw->getChild(FunctionTypeSyntax::Cursor::ReturnType)->isType()); } -RC -FunctionTypeSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - return RC { - new FunctionTypeSyntaxData { Raw, Parent, IndexInParent } - }; -} - -RC FunctionTypeSyntaxData::makeBlank() { - return make(RawSyntax::make(SyntaxKind::FunctionType, +FunctionTypeSyntax FunctionTypeSyntax::makeBlank() { + return make(RawSyntax::make(SyntaxKind::FunctionType, { RawSyntax::missing(SyntaxKind::TypeAttributes), - TokenSyntax::missingToken(tok::l_paren, "("), + RawTokenSyntax::missingToken(tok::l_paren, "("), RawSyntax::missing(SyntaxKind::FunctionParameterList), - TokenSyntax::missingToken(tok::r_paren, ")"), - TokenSyntax::missingToken(tok::kw_throws, "throws"), - TokenSyntax::missingToken(tok::arrow, "->"), + RawTokenSyntax::missingToken(tok::r_paren, ")"), + RawTokenSyntax::missingToken(tok::kw_throws, "throws"), + RawTokenSyntax::missingToken(tok::arrow, "->"), RawSyntax::missing(SyntaxKind::MissingType), }, SourcePresence::Present)); } -#pragma mark - function-type API - -FunctionTypeSyntax::FunctionTypeSyntax(RC Root, - const FunctionTypeSyntaxData *Data) - : TypeSyntax(Root, Data) {} - FunctionTypeSyntax FunctionTypeSyntax:: withTypeAttributes(TypeAttributesSyntax NewAttributes) const { auto NewRaw = getRaw()->replaceChild(Cursor::TypeAttributes, @@ -933,65 +681,61 @@ withTypeAttributes(TypeAttributesSyntax NewAttributes) const { } FunctionTypeSyntax -FunctionTypeSyntax::withLeftArgumentsParen(RC NewLeftParen) const { +FunctionTypeSyntax::withLeftArgumentsParen(TokenSyntax NewLeftParen) const { syntax_assert_token_is(NewLeftParen, tok::l_paren, "("); - auto NewRaw = getRaw()->replaceChild(Cursor::LeftParen, NewLeftParen); - return Data->replaceSelf(NewRaw); + return Data->replaceChild(NewLeftParen.getRaw(), + Cursor::LeftParen); } FunctionTypeSyntax FunctionTypeSyntax:: -addTypeArgument(llvm::Optional> MaybeComma, +addTypeArgument(llvm::Optional MaybeComma, FunctionTypeArgumentSyntax NewArgument) const { auto ArgList = getRaw()->getChild(Cursor::ArgumentList); if (MaybeComma.hasValue()) { syntax_assert_token_is(MaybeComma.getValue(), tok::comma, ","); - ArgList = ArgList->append(MaybeComma.getValue()); + ArgList = ArgList->append(MaybeComma->getRaw()); } else { if (!ArgList->Layout.empty()) { - ArgList = ArgList->append(TokenSyntax::missingToken(tok::comma, ",")); + ArgList = ArgList->append(RawTokenSyntax::missingToken(tok::comma, ",")); } } ArgList = ArgList->append(NewArgument.getRaw()); - auto NewRaw = getRaw()->replaceChild(Cursor::ArgumentList, ArgList); - return Data->replaceSelf(NewRaw); + return Data->replaceChild(ArgList, Cursor::ArgumentList); } FunctionTypeSyntax FunctionTypeSyntax:: -withRightArgumentsParen(RC NewLeftParen) const { +withRightArgumentsParen(TokenSyntax NewLeftParen) const { syntax_assert_token_is(NewLeftParen, tok::r_paren, ")"); - auto NewRaw = getRaw()->replaceChild(Cursor::RightParen, NewLeftParen); - return Data->replaceSelf(NewRaw); + return Data->replaceChild(NewLeftParen.getRaw(), + Cursor::RightParen); } FunctionTypeSyntax -FunctionTypeSyntax::withThrowsKeyword(RC NewThrowsKeyword) const { +FunctionTypeSyntax::withThrowsKeyword(TokenSyntax NewThrowsKeyword) const { syntax_assert_token_is(NewThrowsKeyword, tok::kw_throws, "throws"); - auto NewRaw = getRaw()->replaceChild(Cursor::ThrowsOrRethrows, - NewThrowsKeyword); - return Data->replaceSelf(NewRaw); + return Data->replaceChild(NewThrowsKeyword.getRaw(), + Cursor::ThrowsOrRethrows); } FunctionTypeSyntax FunctionTypeSyntax:: -withRethrowsKeyword(RC NewThrowsKeyword) const { +withRethrowsKeyword(TokenSyntax NewThrowsKeyword) const { syntax_assert_token_is(NewThrowsKeyword, tok::kw_rethrows, "rethrows"); - auto NewRaw = getRaw()->replaceChild(Cursor::ThrowsOrRethrows, - NewThrowsKeyword); - return Data->replaceSelf(NewRaw); + return Data->replaceChild(NewThrowsKeyword.getRaw(), + Cursor::ThrowsOrRethrows); } FunctionTypeSyntax -FunctionTypeSyntax::withArrow(RC NewArrow) const { +FunctionTypeSyntax::withArrow(TokenSyntax NewArrow) const { syntax_assert_token_is(NewArrow, tok::arrow, "->"); - auto NewRaw = getRaw()->replaceChild(Cursor::Arrow, NewArrow); - return Data->replaceSelf(NewRaw); + return Data->replaceChild(NewArrow.getRaw(), + Cursor::Arrow); } FunctionTypeSyntax FunctionTypeSyntax::withReturnTypeSyntax(TypeSyntax NewReturnTypeSyntax) const { - auto NewRaw = getRaw()->replaceChild(Cursor::ReturnType, - NewReturnTypeSyntax.getRaw()); - return Data->replaceSelf(NewRaw); + return Data->replaceChild(NewReturnTypeSyntax.getRaw(), + Cursor::ReturnType); } #pragma mark - function-type Builder @@ -1008,33 +752,34 @@ FunctionTypeSyntaxBuilder &FunctionTypeSyntaxBuilder::useTypeAttributes( } FunctionTypeSyntaxBuilder & -FunctionTypeSyntaxBuilder::useLeftArgumentsParen(RC NewLeftParen) { +FunctionTypeSyntaxBuilder::useLeftArgumentsParen(TokenSyntax NewLeftParen) { syntax_assert_token_is(NewLeftParen, tok::l_paren, "("); auto Index = cursorIndex(FunctionTypeSyntax::Cursor::LeftParen); - FunctionTypeLayout[Index] = NewLeftParen; + FunctionTypeLayout[Index] = NewLeftParen.getRaw(); return *this; } FunctionTypeSyntaxBuilder &FunctionTypeSyntaxBuilder:: -useRightArgumentsParen(RC NewRightParen) { +useRightArgumentsParen(TokenSyntax NewRightParen) { syntax_assert_token_is(NewRightParen, tok::r_paren, ")"); auto Index = cursorIndex(FunctionTypeSyntax::Cursor::RightParen); - FunctionTypeLayout[Index] = NewRightParen; + FunctionTypeLayout[Index] = NewRightParen.getRaw(); return *this; } FunctionTypeSyntaxBuilder &FunctionTypeSyntaxBuilder:: -addArgumentTypeSyntax(Optional> MaybeComma, +addArgumentTypeSyntax(Optional MaybeComma, FunctionTypeArgumentSyntax NewTypeArgument) { auto Index = cursorIndex(FunctionTypeSyntax::Cursor::ArgumentList); auto TypeArgumentsLayout = FunctionTypeLayout[Index]->Layout; if (MaybeComma.hasValue()) { syntax_assert_token_is(MaybeComma.getValue(), tok::comma, ","); - TypeArgumentsLayout.push_back(MaybeComma.getValue()); + TypeArgumentsLayout.push_back(MaybeComma->getRaw()); } else { if (TypeArgumentsLayout.empty()) { - TypeArgumentsLayout.push_back(TokenSyntax::missingToken(tok::comma, ",")); + TypeArgumentsLayout.push_back(RawTokenSyntax::missingToken(tok::comma, + ",")); } } @@ -1047,26 +792,26 @@ addArgumentTypeSyntax(Optional> MaybeComma, } FunctionTypeSyntaxBuilder & -FunctionTypeSyntaxBuilder::useThrowsKeyword(RC NewThrowsKeyword) { +FunctionTypeSyntaxBuilder::useThrowsKeyword(TokenSyntax NewThrowsKeyword) { syntax_assert_token_is(NewThrowsKeyword, tok::kw_throws, "throws"); auto Index = cursorIndex(FunctionTypeSyntax::Cursor::ThrowsOrRethrows); - FunctionTypeLayout[Index] = NewThrowsKeyword; + FunctionTypeLayout[Index] = NewThrowsKeyword.getRaw(); return *this; } FunctionTypeSyntaxBuilder & -FunctionTypeSyntaxBuilder::useRethrowsKeyword(RC NewRethrowsKeyword) { +FunctionTypeSyntaxBuilder::useRethrowsKeyword(TokenSyntax NewRethrowsKeyword) { syntax_assert_token_is(NewRethrowsKeyword, tok::kw_rethrows, "rethrows"); auto Index = cursorIndex(FunctionTypeSyntax::Cursor::ThrowsOrRethrows); - FunctionTypeLayout[Index] = NewRethrowsKeyword; + FunctionTypeLayout[Index] = NewRethrowsKeyword.getRaw(); return *this; } FunctionTypeSyntaxBuilder & -FunctionTypeSyntaxBuilder::useArrow(RC NewArrow) { +FunctionTypeSyntaxBuilder::useArrow(TokenSyntax NewArrow) { syntax_assert_token_is(NewArrow, tok::arrow, "->"); auto Index = cursorIndex(FunctionTypeSyntax::Cursor::Arrow); - FunctionTypeLayout[Index] = NewArrow; + FunctionTypeLayout[Index] = NewArrow.getRaw(); return *this; } @@ -1080,6 +825,5 @@ FunctionTypeSyntaxBuilder::useReturnTypeSyntax(TypeSyntax NewReturnType) { FunctionTypeSyntax FunctionTypeSyntaxBuilder::build() const { auto Raw = RawSyntax::make(SyntaxKind::FunctionType, FunctionTypeLayout, SourcePresence::Present); - auto Data = FunctionTypeSyntaxData::make(Raw); - return { Data, Data.get() }; + return make(Raw); } diff --git a/lib/Syntax/UnknownSyntax.cpp b/lib/Syntax/UnknownSyntax.cpp index 6533926db8c..ec69976b30e 100644 --- a/lib/Syntax/UnknownSyntax.cpp +++ b/lib/Syntax/UnknownSyntax.cpp @@ -16,84 +16,39 @@ using namespace swift; using namespace swift::syntax; -#pragma mark - unknown-syntax Data - -UnknownSyntaxData::UnknownSyntaxData(const RC Raw, - const SyntaxData *Parent, - const CursorIndex IndexInParent) - : SyntaxData(Raw, Parent, IndexInParent) { - assert(Raw->isUnknown()); - for (auto RawChild : Raw->Layout) { - if (!RawChild->isToken()) { - CachedChildren.emplace_back(nullptr); - } - } -} - -RC UnknownSyntaxData::make(RC Raw, - const SyntaxData *Parent, - CursorIndex IndexInParent) { - - auto UnknownRaw = RawSyntax::make(SyntaxKind::Unknown, Raw->Layout, - Raw->Presence); - - return RC { - new UnknownSyntaxData { UnknownRaw, Parent, IndexInParent } - }; +void UnknownSyntax::validate() const { + assert(Data->Raw->isUnknown()); } #pragma mark - unknown-syntax API -UnknownSyntax::UnknownSyntax(const RC Root, - const UnknownSyntaxData *Data) - : Syntax(Root, Data) {} - size_t UnknownSyntax::getNumChildren() const { - size_t Count = 0; + size_t NonTokenChildren = 0; for (auto Child : getRaw()->Layout) { - if (Child->isToken()) { - continue; + if (!Child->isToken()) { + ++NonTokenChildren; } - ++Count; } - return Count; + return NonTokenChildren; } Syntax UnknownSyntax::getChild(const size_t N) const { - auto *MyData = getUnsafeData(); - - if (auto RealizedChild = MyData->CachedChildren[N]) { - return Syntax { Root, RealizedChild.get() }; - } - - assert(N < getNumChildren()); - assert(N < getRaw()->Layout.size()); - - CursorIndex ChildLayoutIndex = 0; - - for (size_t LayoutIndex = 0, Left = N; - LayoutIndex < getRaw()->Layout.size(); - ++LayoutIndex) { - auto Child = getRaw()->Layout[LayoutIndex]; - if (Child->isToken()) { - continue; + // The actual index of the Nth non-token child. + size_t ActualIndex = 0; + // The number of non-token children we've seen. + size_t NumNonTokenSeen = 0; + for (auto Child : getRaw()->Layout) { + // If we see a child that's not a token, count it. + if (!Child->isToken()) { + ++NumNonTokenSeen; } - ChildLayoutIndex = LayoutIndex; - if (Left == 0) { - break; - } - --Left; + // If the number of children we've seen indexes the same (count - 1) as + // the number we're looking for, then we're done. + if (NumNonTokenSeen == N + 1) { break; } + + // Otherwise increment the actual index and keep searching. + ++ActualIndex; } - - auto RawChild = getRaw()->Layout[ChildLayoutIndex]; - assert(RawChild->Kind != SyntaxKind::Token); - - auto &ChildPtr = *reinterpret_cast*>( - MyData->CachedChildren.data() + N); - - SyntaxData::realizeSyntaxNode(ChildPtr, RawChild, MyData, - ChildLayoutIndex); - - return Syntax { Root, MyData->CachedChildren[N].get() }; + return Syntax { Root, Data->getChild(ActualIndex).get() }; } diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp index f27bdd2cc6c..7c2324adc2b 100644 --- a/lib/TBDGen/TBDGen.cpp +++ b/lib/TBDGen/TBDGen.cpp @@ -24,6 +24,7 @@ #include "swift/IRGen/Linking.h" #include "swift/SIL/FormalLinkage.h" #include "swift/SIL/SILDeclRef.h" +#include "swift/SIL/SILWitnessTable.h" #include "swift/SIL/TypeLowering.h" #include "llvm/ADT/StringSet.h" @@ -41,6 +42,7 @@ class TBDGenVisitor : public ASTVisitor { const UniversalLinkageInfo &UniversalLinkInfo; ModuleDecl *SwiftModule; bool FileHasEntryPoint; + bool SILSerializeWitnessTables; void addSymbol(StringRef name) { auto isNewValue = Symbols.insert(name).second; @@ -62,29 +64,16 @@ class TBDGenVisitor : public ASTVisitor { addSymbol(linkage.getName()); } - void addConformances(DeclContext *DC) { - for (auto conformance : DC->getLocalConformances()) { - auto needsWTable = Lowering::TypeConverter::protocolRequiresWitnessTable( - conformance->getProtocol()); - if (!needsWTable) - continue; - - // Only normal conformances get symbols; the others get any public symbols - // from their parent normal conformance. - if (conformance->getKind() != ProtocolConformanceKind::Normal) - continue; - - addSymbol(LinkEntity::forDirectProtocolWitnessTable(conformance)); - addSymbol(LinkEntity::forProtocolWitnessTableAccessFunction(conformance)); - } - } + void addConformances(DeclContext *DC); public: TBDGenVisitor(StringSet &symbols, const UniversalLinkageInfo &universalLinkInfo, - ModuleDecl *swiftModule, bool fileHasEntryPoint) + ModuleDecl *swiftModule, bool fileHasEntryPoint, + bool silSerializeWitnessTables) : Symbols(symbols), UniversalLinkInfo(universalLinkInfo), - SwiftModule(swiftModule), FileHasEntryPoint(fileHasEntryPoint) {} + SwiftModule(swiftModule), FileHasEntryPoint(fileHasEntryPoint), + SILSerializeWitnessTables(silSerializeWitnessTables) {} void visitMembers(Decl *D) { SmallVector members; @@ -96,6 +85,8 @@ public: addMembers(ED->getMembers()); else if (auto NTD = dyn_cast(D)) addMembers(NTD->getMembers()); + else if (auto VD = dyn_cast(D)) + VD->getAllAccessorFunctions(members); for (auto member : members) { ASTVisitor::visit(member); @@ -160,10 +151,6 @@ void TBDGenVisitor::addSymbol(SILDeclRef declRef, bool checkSILOnly) { // currently need to refer to them by symbol for their own vtable. switch (declRef.getSubclassScope()) { case SubclassScope::External: - // Allocating constructors retain their normal linkage behavior. - if (declRef.kind == SILDeclRef::Kind::Allocator) - break; - // Unlike the "truly" public things, private things have public symbols // unconditionally, even if they're theoretically SIL only. if (isPrivate) { @@ -186,6 +173,83 @@ void TBDGenVisitor::addSymbol(SILDeclRef declRef, bool checkSILOnly) { addSymbol(declRef.mangle()); } +void TBDGenVisitor::addConformances(DeclContext *DC) { + for (auto conformance : DC->getLocalConformances()) { + auto protocol = conformance->getProtocol(); + auto needsWTable = + Lowering::TypeConverter::protocolRequiresWitnessTable(protocol); + if (!needsWTable) + continue; + + // Only normal conformances get symbols; the others get any public symbols + // from their parent normal conformance. + auto normalConformance = dyn_cast(conformance); + if (!normalConformance) + continue; + + addSymbol(LinkEntity::forDirectProtocolWitnessTable(normalConformance)); + addSymbol( + LinkEntity::forProtocolWitnessTableAccessFunction(normalConformance)); + + // FIXME: the logic around visibility in extensions is confusing, and + // sometimes witness thunks need to be manually made public. + + auto conformanceIsFixed = SILWitnessTable::conformanceIsSerialized( + normalConformance, SwiftModule->getResilienceStrategy(), + SILSerializeWitnessTables); + auto addSymbolIfNecessary = [&](ValueDecl *valueReq, + SILLinkage witnessLinkage) { + if (conformanceIsFixed && + fixmeWitnessHasLinkageThatNeedsToBePublic(witnessLinkage)) { + Mangle::ASTMangler Mangler; + addSymbol(Mangler.mangleWitnessThunk(normalConformance, valueReq)); + } + }; + normalConformance->forEachValueWitness(nullptr, [&](ValueDecl *valueReq, + Witness witness) { + if (isa(valueReq)) { + auto witnessLinkage = + SILDeclRef(witness.getDecl()).getLinkage(ForDefinition); + addSymbolIfNecessary(valueReq, witnessLinkage); + } else if (auto VD = dyn_cast(valueReq)) { + // A var or subscript decl needs extra special handling: the things that + // end up in the witness table are the accessors, but the compiler only + // talks about the actual storage decl in the conformance, so we have to + // manually walk over the members, having pulled out something that will + // have the right linkage. + auto witnessVD = cast(witness.getDecl()); + + SmallVector members; + VD->getAllAccessorFunctions(members); + + // Grab one of the accessors, and then use that to pull out which of the + // getter or setter will have the appropriate linkage. + FuncDecl *witnessWithRelevantLinkage; + switch (cast(members[0])->getAccessorKind()) { + case AccessorKind::NotAccessor: + llvm_unreachable("must be an accessor"); + case AccessorKind::IsGetter: + case AccessorKind::IsAddressor: + witnessWithRelevantLinkage = witnessVD->getGetter(); + break; + case AccessorKind::IsSetter: + case AccessorKind::IsWillSet: + case AccessorKind::IsDidSet: + case AccessorKind::IsMaterializeForSet: + case AccessorKind::IsMutableAddressor: + witnessWithRelevantLinkage = witnessVD->getSetter(); + break; + } + auto witnessLinkage = + SILDeclRef(witnessWithRelevantLinkage).getLinkage(ForDefinition); + for (auto member : members) { + addSymbolIfNecessary(cast(member), witnessLinkage); + } + } + }); + } +} + void TBDGenVisitor::visitValueDecl(ValueDecl *VD) { addSymbol(SILDeclRef(VD)); visitMembers(VD); @@ -225,9 +289,11 @@ void TBDGenVisitor::visitVarDecl(VarDecl *VD) { // like globals. if (!FileHasEntryPoint) addSymbol(SILDeclRef(VD, SILDeclRef::Kind::GlobalAccessor)); - } - visitMembers(VD); + // In this case, the members of the VarDecl don't also appear as top-level + // decls, so we need to explicitly walk them. + visitMembers(VD); + } } void TBDGenVisitor::visitNominalTypeDecl(NominalTypeDecl *NTD) { @@ -281,9 +347,11 @@ void TBDGenVisitor::visitClassDecl(ClassDecl *CD) { auto hasFieldOffset = !isGeneric && var && var->hasStorage() && !var->isStatic(); if (hasFieldOffset) { - // Field are only direct if the class's internals are completely known. - auto isIndirect = !CD->hasFixedLayout(); - addSymbol(LinkEntity::forFieldOffset(var, isIndirect)); + // FIXME: a field only has one sort of offset, but it is moderately + // non-trivial to compute which one. Including both is less painful than + // missing the correct one (for now), so we do that. + addSymbol(LinkEntity::forFieldOffset(var, /*isIndirect=*/false)); + addSymbol(LinkEntity::forFieldOffset(var, /*isIndirect=*/true)); } // The non-allocating forms of the constructors and destructors. @@ -328,7 +396,8 @@ void TBDGenVisitor::visitProtocolDecl(ProtocolDecl *PD) { void swift::enumeratePublicSymbols(FileUnit *file, StringSet &symbols, bool hasMultipleIRGenThreads, - bool isWholeModule) { + bool isWholeModule, + bool silSerializeWitnessTables) { UniversalLinkageInfo linkInfo(file->getASTContext().LangOpts.Target, hasMultipleIRGenThreads, isWholeModule); @@ -338,7 +407,7 @@ void swift::enumeratePublicSymbols(FileUnit *file, StringSet &symbols, auto hasEntryPoint = file->hasEntryPoint(); TBDGenVisitor visitor(symbols, linkInfo, file->getParentModule(), - hasEntryPoint); + hasEntryPoint, silSerializeWitnessTables); for (auto d : decls) visitor.visit(d); diff --git a/stdlib/CMakeLists.txt b/stdlib/CMakeLists.txt index 5c2400746cf..fe2064e008f 100644 --- a/stdlib/CMakeLists.txt +++ b/stdlib/CMakeLists.txt @@ -93,11 +93,14 @@ add_custom_target(swift-test-stdlib ALL if(SWIFT_STDLIB_ENABLE_RESILIENCE) set(STDLIB_SIL_SERIALIZE_ALL) + set(STDLIB_SIL_SERIALIZE_WITNESS_TABLES) else() if(SWIFT_STDLIB_SIL_SERIALIZE_ALL) set(STDLIB_SIL_SERIALIZE_ALL "-Xfrontend" "-sil-serialize-all") + set(STDLIB_SIL_SERIALIZE_WITNESS_TABLES "-Xfrontend" "-sil-serialize-witness-tables") else() set(STDLIB_SIL_SERIALIZE_ALL) + set(STDLIB_SIL_SERIALIZE_WITNESS_TABLES) endif() endif() diff --git a/stdlib/private/StdlibUnittest/RaceTest.swift b/stdlib/private/StdlibUnittest/RaceTest.swift index e88288d2786..08d1938402e 100644 --- a/stdlib/private/StdlibUnittest/RaceTest.swift +++ b/stdlib/private/StdlibUnittest/RaceTest.swift @@ -41,7 +41,7 @@ import SwiftPrivateLibcExtras import SwiftPrivatePthreadExtras #if os(OSX) || os(iOS) import Darwin -#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || CYGWIN +#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) import Glibc #endif diff --git a/stdlib/private/StdlibUnittest/StdlibCoreExtras.swift b/stdlib/private/StdlibUnittest/StdlibCoreExtras.swift index 7307e81e9d7..960d1ffc9ce 100644 --- a/stdlib/private/StdlibUnittest/StdlibCoreExtras.swift +++ b/stdlib/private/StdlibUnittest/StdlibCoreExtras.swift @@ -14,7 +14,7 @@ import SwiftPrivate import SwiftPrivateLibcExtras #if os(OSX) || os(iOS) import Darwin -#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || CYGWIN +#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) import Glibc #endif diff --git a/stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb b/stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb index d8e130c7b16..5f7d2748f26 100644 --- a/stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb +++ b/stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb @@ -20,7 +20,7 @@ import SwiftPrivateLibcExtras #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) import Darwin -#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || CYGWIN +#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) import Glibc #endif @@ -1497,7 +1497,7 @@ func _getOSVersion() -> OSVersion { return .ps4 #elseif os(Android) return .android -#elseif os(Windows) && CYGWIN +#elseif os(Cygwin) return .windowsCygnus #elseif os(Windows) return .windows diff --git a/stdlib/private/SwiftPrivateLibcExtras/Subprocess.swift b/stdlib/private/SwiftPrivateLibcExtras/Subprocess.swift index 618e24b46a2..e4350d92d25 100644 --- a/stdlib/private/SwiftPrivateLibcExtras/Subprocess.swift +++ b/stdlib/private/SwiftPrivateLibcExtras/Subprocess.swift @@ -13,13 +13,14 @@ import SwiftPrivate #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) import Darwin -#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || CYGWIN +#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) import Glibc #endif -#if !os(Windows) || CYGWIN -// posix_spawn is not available on Android or Windows. +#if !os(Windows) +// posix_spawn is not available on Windows. +// posix_spawn is not available on Android. #if !os(Android) // swift_posix_spawn isn't available in the public watchOS SDK, we sneak by the // unavailable attribute declaration here of the APIs that we need. @@ -264,7 +265,7 @@ public enum ProcessTerminationStatus : CustomStringConvertible { public func posixWaitpid(_ pid: pid_t) -> ProcessTerminationStatus { var status: CInt = 0 -#if CYGWIN +#if os(Cygwin) withUnsafeMutablePointer(to: &status) { statusPtr in let statusPtrWrapper = __wait_status_ptr_t(__int_ptr: statusPtr) @@ -304,7 +305,7 @@ internal func _getEnviron() -> UnsafeMutablePointer? return environ #elseif os(Android) return environ -#elseif CYGWIN +#elseif os(Cygwin) return environ #else return __environ diff --git a/stdlib/private/SwiftPrivateLibcExtras/SwiftPrivateLibcExtras.swift b/stdlib/private/SwiftPrivateLibcExtras/SwiftPrivateLibcExtras.swift index 2850883eff6..8d4412fb5cb 100644 --- a/stdlib/private/SwiftPrivateLibcExtras/SwiftPrivateLibcExtras.swift +++ b/stdlib/private/SwiftPrivateLibcExtras/SwiftPrivateLibcExtras.swift @@ -13,13 +13,13 @@ import SwiftPrivate #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) import Darwin -#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || CYGWIN +#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) import Glibc #elseif os(Windows) import ucrt #endif -#if !os(Windows) || CYGWIN +#if !os(Windows) public func _stdlib_mkstemps(_ template: inout String, _ suffixlen: CInt) -> CInt { #if os(Android) preconditionFailure("mkstemps doesn't work on Android") @@ -85,7 +85,7 @@ public struct _stdlib_fd_set { } } -#if !os(Windows) || CYGWIN +#if !os(Windows) public func _stdlib_select( _ readfds: inout _stdlib_fd_set, _ writefds: inout _stdlib_fd_set, _ errorfds: inout _stdlib_fd_set, _ timeout: UnsafeMutablePointer? @@ -99,7 +99,7 @@ public func _stdlib_select( let readAddr = readfds.baseAddress let writeAddr = writefds.baseAddress let errorAddr = errorfds.baseAddress -#if CYGWIN +#if os(Cygwin) typealias fd_set = _types_fd_set #endif func asFdSetPtr( @@ -125,10 +125,10 @@ public func _stdlib_select( public func _stdlib_pipe() -> (readEnd: CInt, writeEnd: CInt, error: CInt) { var fds: [CInt] = [0, 0] let ret = fds.withUnsafeMutableBufferPointer { unsafeFds -> CInt in -#if !os(Windows) || CYGWIN - return pipe(unsafeFds.baseAddress) -#else +#if os(Windows) return _pipe(unsafeFds.baseAddress, 0, 0) +#else + return pipe(unsafeFds.baseAddress) #endif } return (readEnd: fds[0], writeEnd: fds[1], error: ret) diff --git a/stdlib/private/SwiftPrivatePthreadExtras/PthreadBarriers.swift b/stdlib/private/SwiftPrivatePthreadExtras/PthreadBarriers.swift index 2ebe4b3acca..df922f9a887 100644 --- a/stdlib/private/SwiftPrivatePthreadExtras/PthreadBarriers.swift +++ b/stdlib/private/SwiftPrivatePthreadExtras/PthreadBarriers.swift @@ -12,7 +12,7 @@ #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) import Darwin -#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || CYGWIN +#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) import Glibc #endif @@ -43,7 +43,7 @@ public var _stdlib_PTHREAD_BARRIER_SERIAL_THREAD: CInt { } public struct _stdlib_pthread_barrier_t { -#if CYGWIN || os(FreeBSD) +#if os(Cygwin) || os(FreeBSD) var mutex: UnsafeMutablePointer? var cond: UnsafeMutablePointer? #else diff --git a/stdlib/private/SwiftPrivatePthreadExtras/SwiftPrivatePthreadExtras.swift b/stdlib/private/SwiftPrivatePthreadExtras/SwiftPrivatePthreadExtras.swift index fe0c4f06586..26809a042e9 100644 --- a/stdlib/private/SwiftPrivatePthreadExtras/SwiftPrivatePthreadExtras.swift +++ b/stdlib/private/SwiftPrivatePthreadExtras/SwiftPrivatePthreadExtras.swift @@ -17,7 +17,7 @@ #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) import Darwin -#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || CYGWIN +#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) import Glibc #endif @@ -59,7 +59,7 @@ internal func invokeBlockContext( return context.run() } -#if CYGWIN || os(FreeBSD) +#if os(Cygwin) || os(FreeBSD) public typealias _stdlib_pthread_attr_t = UnsafePointer #else public typealias _stdlib_pthread_attr_t = UnsafePointer diff --git a/stdlib/public/Platform/Darwin.swift.gyb b/stdlib/public/Platform/Darwin.swift.gyb index 9c627a75e7f..4d4604b2388 100644 --- a/stdlib/public/Platform/Darwin.swift.gyb +++ b/stdlib/public/Platform/Darwin.swift.gyb @@ -74,7 +74,8 @@ public let ${prefix}_TRUE_MIN = ${type}.leastNonzeroMagnitude // Macros defined in bsd/sys/proc.h that do not import into Swift. extension extern_proc { // #define p_starttime p_un.__p_starttime - @_transparent var p_starttime: timeval { + @_transparent + public var p_starttime: timeval { get { return self.p_un.__p_starttime } set { self.p_un.__p_starttime = newValue } } diff --git a/stdlib/public/Platform/Platform.swift b/stdlib/public/Platform/Platform.swift index 1512aa04bb1..fd7c6605e22 100644 --- a/stdlib/public/Platform/Platform.swift +++ b/stdlib/public/Platform/Platform.swift @@ -141,23 +141,23 @@ public func snprintf(ptr: UnsafeMutablePointer, _ len: Int, _ format: Unsa // fcntl.h //===----------------------------------------------------------------------===// -#if !os(Windows) || CYGWIN -@_silgen_name("_swift_Platform_open") -func _swift_Platform_open( - _ path: UnsafePointer, - _ oflag: Int32, - _ mode: mode_t -) -> Int32 -#else +#if os(Windows) @_silgen_name("_swift_Platform_open") func _swift_Platform_open( _ path: UnsafePointer, _ oflag: Int32, _ mode: Int32 ) -> Int32 +#else +@_silgen_name("_swift_Platform_open") +func _swift_Platform_open( + _ path: UnsafePointer, + _ oflag: Int32, + _ mode: mode_t +) -> Int32 #endif -#if !os(Windows) || CYGWIN +#if !os(Windows) @_silgen_name("_swift_Platform_openat") func _swift_Platform_openat( _ fd: Int32, @@ -174,7 +174,15 @@ public func open( return _swift_Platform_open(path, oflag, 0) } -#if !os(Windows) || CYGWIN +#if os(Windows) +public func open( + _ path: UnsafePointer, + _ oflag: Int32, + _ mode: Int32 +) -> Int32 { + return _swift_Platform_open(path, oflag, mode) +} +#else public func open( _ path: UnsafePointer, _ oflag: Int32, @@ -199,17 +207,9 @@ public func openat( ) -> Int32 { return _swift_Platform_openat(fd, path, oflag, mode) } -#else -public func open( - _ path: UnsafePointer, - _ oflag: Int32, - _ mode: Int32 -) -> Int32 { - return _swift_Platform_open(path, oflag, mode) -} #endif -#if !os(Windows) || CYGWIN +#if !os(Windows) @_silgen_name("_swift_Platform_fcntl") internal func _swift_Platform_fcntl( _ fd: Int32, @@ -248,7 +248,18 @@ public func fcntl( } #endif -#if !os(Windows) || CYGWIN +#if os(Windows) +public var S_IFMT: Int32 { return Int32(0xf000) } + +public var S_IFREG: Int32 { return Int32(0x8000) } +public var S_IFDIR: Int32 { return Int32(0x4000) } +public var S_IFCHR: Int32 { return Int32(0x2000) } +public var S_IFIFO: Int32 { return Int32(0x1000) } + +public var S_IREAD: Int32 { return Int32(0x0100) } +public var S_IWRITE: Int32 { return Int32(0x0080) } +public var S_IEXEC: Int32 { return Int32(0x0040) } +#else public var S_IFMT: mode_t { return mode_t(0o170000) } public var S_IFIFO: mode_t { return mode_t(0o010000) } public var S_IFCHR: mode_t { return mode_t(0o020000) } @@ -286,24 +297,13 @@ public var S_IREAD: mode_t { return S_IRUSR } public var S_IWRITE: mode_t { return S_IWUSR } public var S_IEXEC: mode_t { return S_IXUSR } #endif -#else -public var S_IFMT: Int32 { return Int32(0xf000) } - -public var S_IFREG: Int32 { return Int32(0x8000) } -public var S_IFDIR: Int32 { return Int32(0x4000) } -public var S_IFCHR: Int32 { return Int32(0x2000) } -public var S_IFIFO: Int32 { return Int32(0x1000) } - -public var S_IREAD: Int32 { return Int32(0x0100) } -public var S_IWRITE: Int32 { return Int32(0x0080) } -public var S_IEXEC: Int32 { return Int32(0x0040) } #endif //===----------------------------------------------------------------------===// // ioctl.h //===----------------------------------------------------------------------===// -#if !os(Windows) || CYGWIN +#if !os(Windows) @_silgen_name("_swift_Platform_ioctl") internal func _swift_Platform_ioctl( _ fd: CInt, @@ -380,8 +380,7 @@ public var SIG_ERR: sighandler_t { public var SIG_HOLD: sighandler_t { return unsafeBitCast(2, to: sighandler_t.self) } -#elseif os(Windows) -#if CYGWIN +#elseif os(Cygwin) public typealias sighandler_t = _sig_func_ptr public var SIG_DFL: sighandler_t? { return nil } @@ -394,7 +393,7 @@ public var SIG_ERR: sighandler_t { public var SIG_HOLD: sighandler_t { return unsafeBitCast(2, to: sighandler_t.self) } -#else +#elseif os(Windows) public var SIG_DFL: _crt_signal_t? { return nil } public var SIG_IGN: _crt_signal_t { return unsafeBitCast(1, to: _crt_signal_t.self) @@ -402,7 +401,6 @@ public var SIG_IGN: _crt_signal_t { public var SIG_ERR: _crt_signal_t { return unsafeBitCast(-1, to: _crt_signal_t.self) } -#endif #else internal var _ignore = _UnsupportedPlatformError() #endif @@ -411,13 +409,13 @@ internal var _ignore = _UnsupportedPlatformError() // semaphore.h //===----------------------------------------------------------------------===// -#if !os(Windows) || CYGWIN +#if !os(Windows) /// The value returned by `sem_open()` in the case of failure. public var SEM_FAILED: UnsafeMutablePointer? { #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) // The value is ABI. Value verified to be correct for OS X, iOS, watchOS, tvOS. return UnsafeMutablePointer(bitPattern: -1) -#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || CYGWIN +#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) // The value is ABI. Value verified to be correct on Glibc. return UnsafeMutablePointer(bitPattern: 0) #else diff --git a/stdlib/public/Platform/tgmath.swift.gyb b/stdlib/public/Platform/tgmath.swift.gyb index 6f442044602..34bd5443fe6 100644 --- a/stdlib/public/Platform/tgmath.swift.gyb +++ b/stdlib/public/Platform/tgmath.swift.gyb @@ -216,13 +216,13 @@ public func fpclassify(_ value: ${T}) -> Int { %if T == 'Double': #if os(Linux) return Int(__fpclassify(CDouble(value))) -#elseif os(Windows) && !CYGWIN +#elseif os(Windows) return Int(_dclass(CDouble(value))) #else return Int(__fpclassifyd(CDouble(value))) #endif %else: -#if os(Windows) && !CYGWIN +#if os(Windows) return Int(_${f}dclass(${CT}(value))) #else return Int(__fpclassify${f}(${CT}(value))) @@ -298,7 +298,7 @@ public func scalbn(_ x: ${T}, _ n: Int) -> ${T} { % # This is AllFloatTypes not OverlayFloatTypes because of the tuple return. % for T, CT, f in AllFloatTypes(): -#if os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || CYGWIN +#if os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) @_transparent public func lgamma(_ x: ${T}) -> (${T}, Int) { var sign = Int32(0) @@ -306,16 +306,7 @@ public func lgamma(_ x: ${T}) -> (${T}, Int) { return (${T}(value), Int(sign)) } #elseif os(Windows) -#if CYGWIN -@_transparent -public func lgamma(_ x: ${T}) -> (${T}, Int) { - var sign = Int32(0) - let value = lgamma${f}_r(${CT}(x), &sign) - return (${T}(value), Int(sign)) -} -#else // TODO(compnerd): implement -#endif #else % # On Darwin platform, % # The real lgamma_r is not imported because it hides behind macro _REENTRANT. @@ -360,11 +351,7 @@ public func nan(_ tag: String) -> ${T} { @_transparent public func jn(_ n: Int, _ x: Double) -> Double { #if os(Windows) -#if CYGWIN - return jn(Int32(n), x) -#else return _jn(Int32(n), x) -#endif #else return jn(Int32(n), x) #endif @@ -373,11 +360,7 @@ public func jn(_ n: Int, _ x: Double) -> Double { @_transparent public func yn(_ n: Int, _ x: Double) -> Double { #if os(Windows) -#if CYGWIN - return yn(Int32(n), x) -#else return _yn(Int32(n), x) -#endif #else return yn(Int32(n), x) #endif diff --git a/stdlib/public/SDK/CMakeLists.txt b/stdlib/public/SDK/CMakeLists.txt index 3c1d569b5e8..a96ec91234d 100644 --- a/stdlib/public/SDK/CMakeLists.txt +++ b/stdlib/public/SDK/CMakeLists.txt @@ -8,7 +8,9 @@ if(SWIFT_BUILD_STATIC_SDK_OVERLAY) list(APPEND SWIFT_SDK_OVERLAY_LIBRARY_BUILD_TYPES STATIC) endif() -set(all_overlays "Accelerate;AppKit;ARKit;AssetsLibrary;AVFoundation;CallKit;CloudKit;Contacts;CoreAudio;CoreData;CoreFoundation;CoreGraphics;CoreImage;CoreLocation;CoreMedia;CryptoTokenKit;Dispatch;Foundation;GameplayKit;GLKit;HomeKit;IOKit;Intents;MapKit;ObjectiveC;OpenCL;os;Photos;QuartzCore;SafariServices;SceneKit;simd;SpriteKit;UIKit;WatchKit;XCTest;XPC") +list(APPEND SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS "${STDLIB_SIL_SERIALIZE_WITNESS_TABLES}") + +set(all_overlays "Accelerate;AppKit;ARKit;AssetsLibrary;AVFoundation;CallKit;CloudKit;Contacts;CoreAudio;CoreData;CoreFoundation;CoreGraphics;CoreImage;CoreLocation;CoreMedia;CryptoTokenKit;Dispatch;Foundation;GameplayKit;GLKit;HomeKit;IOKit;Intents;MapKit;ModelIO;ObjectiveC;OpenCL;os;Photos;QuartzCore;SafariServices;SceneKit;simd;SpriteKit;UIKit;WatchKit;XCTest;XPC") if(DEFINED SWIFT_OVERLAY_TARGETS) set(overlays_to_build ${SWIFT_OVERLAY_TARGETS}) diff --git a/stdlib/public/SDK/CoreGraphics/CoreGraphics.swift b/stdlib/public/SDK/CoreGraphics/CoreGraphics.swift index abafde2a90c..96943ce2740 100644 --- a/stdlib/public/SDK/CoreGraphics/CoreGraphics.swift +++ b/stdlib/public/SDK/CoreGraphics/CoreGraphics.swift @@ -250,6 +250,21 @@ extension CGPoint : Equatable { } } +extension CGPoint : Codable { + public init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + let x = try container.decode(CGFloat.self) + let y = try container.decode(CGFloat.self) + self.init(x: x, y: y) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.unkeyedContainer() + try container.encode(x) + try container.encode(y) + } +} + public extension CGSize { static var zero: CGSize { @_transparent // @fragile @@ -302,6 +317,21 @@ extension CGSize : Equatable { } } +extension CGSize : Codable { + public init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + let width = try container.decode(CGFloat.self) + let height = try container.decode(CGFloat.self) + self.init(width: width, height: height) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.unkeyedContainer() + try container.encode(width) + try container.encode(height) + } +} + public extension CGVector { static var zero: CGVector { @_transparent // @fragile @@ -332,6 +362,21 @@ extension CGVector : CustomDebugStringConvertible { } } +extension CGVector : Codable { + public init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + let dx = try container.decode(CGFloat.self) + let dy = try container.decode(CGFloat.self) + self.init(dx: dx, dy: dy) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.unkeyedContainer() + try container.encode(dx) + try container.encode(dy) + } +} + public extension CGRect { static var zero: CGRect { @_transparent // @fragile @@ -411,6 +456,21 @@ extension CGRect : Equatable { } } +extension CGRect : Codable { + public init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + let origin = try container.decode(CGPoint.self) + let size = try container.decode(CGSize.self) + self.init(origin: origin, size: size) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.unkeyedContainer() + try container.encode(origin) + try container.encode(size) + } +} + extension CGAffineTransform { public static var identity: CGAffineTransform { @_transparent // @fragile @@ -418,6 +478,29 @@ extension CGAffineTransform { } } +extension CGAffineTransform : Codable { + public init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + let a = try container.decode(CGFloat.self) + let b = try container.decode(CGFloat.self) + let c = try container.decode(CGFloat.self) + let d = try container.decode(CGFloat.self) + let tx = try container.decode(CGFloat.self) + let ty = try container.decode(CGFloat.self) + self.init(a: a, b: b, c: c, d: d, tx: tx, ty: ty) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.unkeyedContainer() + try container.encode(a) + try container.encode(b) + try container.encode(c) + try container.encode(d) + try container.encode(tx) + try container.encode(ty) + } +} + //===----------------------------------------------------------------------===// // CGImage //===----------------------------------------------------------------------===// diff --git a/stdlib/public/SDK/Dispatch/Source.swift b/stdlib/public/SDK/Dispatch/Source.swift index e82a14c0d55..2fab3ea5742 100644 --- a/stdlib/public/SDK/Dispatch/Source.swift +++ b/stdlib/public/SDK/Dispatch/Source.swift @@ -261,28 +261,341 @@ public extension DispatchSourceProcess { } public extension DispatchSourceTimer { + /// + /// Sets the deadline and leeway for a timer event that fires once. + /// + /// Once this function returns, any pending source data accumulated for the previous timer values + /// has been cleared and the next timer event will occur at `deadline`. + /// + /// Delivery of the timer event may be delayed by the system in order to improve power consumption + /// and system performance. The upper limit to the allowable delay may be configured with the `leeway` + /// argument; the lower limit is under the control of the system. + /// + /// The lower limit to the allowable delay may vary with process state such as visibility of the + /// application UI. If the timer source was created with flags `TimerFlags.strict`, the system + /// will make a best effort to strictly observe the provided `leeway` value, even if it is smaller + /// than the current lower limit. Note that a minimal amount of delay is to be expected even if + /// this flag is specified. + /// + /// Calling this method has no effect if the timer source has already been canceled. + /// - note: Delivery of the timer event does not cancel the timer source. + /// + /// - parameter deadline: the time at which the timer event will be delivered, subject to the + /// leeway and other considerations described above. The deadline is based on Mach absolute + /// time. + /// - parameter leeway: the leeway for the timer. + /// + @available(swift, deprecated: 4, renamed: "schedule(deadline:repeating:leeway:)") public func scheduleOneshot(deadline: DispatchTime, leeway: DispatchTimeInterval = .nanoseconds(0)) { __dispatch_source_set_timer(self as! DispatchSource, UInt64(deadline.rawValue), ~0, UInt64(leeway.rawValue)) } + /// + /// Sets the deadline and leeway for a timer event that fires once. + /// + /// Once this function returns, any pending source data accumulated for the previous timer values + /// has been cleared and the next timer event will occur at `wallDeadline`. + /// + /// Delivery of the timer event may be delayed by the system in order to improve power consumption + /// and system performance. The upper limit to the allowable delay may be configured with the `leeway` + /// argument; the lower limit is under the control of the system. + /// + /// The lower limit to the allowable delay may vary with process state such as visibility of the + /// application UI. If the timer source was created with flags `TimerFlags.strict`, the system + /// will make a best effort to strictly observe the provided `leeway` value, even if it is smaller + /// than the current lower limit. Note that a minimal amount of delay is to be expected even if + /// this flag is specified. + /// + /// Calling this method has no effect if the timer source has already been canceled. + /// - note: Delivery of the timer event does not cancel the timer source. + /// + /// - parameter wallDeadline: the time at which the timer event will be delivered, subject to the + /// leeway and other considerations described above. The deadline is based on + /// `gettimeofday(3)`. + /// - parameter leeway: the leeway for the timer. + /// + @available(swift, deprecated: 4, renamed: "schedule(wallDeadline:repeating:leeway:)") public func scheduleOneshot(wallDeadline: DispatchWallTime, leeway: DispatchTimeInterval = .nanoseconds(0)) { __dispatch_source_set_timer(self as! DispatchSource, UInt64(wallDeadline.rawValue), ~0, UInt64(leeway.rawValue)) } - + /// + /// Sets the deadline, interval and leeway for a timer event that fires at least once. + /// + /// Once this function returns, any pending source data accumulated for the previous timer values + /// has been cleared. The next timer event will occur at `deadline` and every `interval` units of + /// time thereafter until the timer source is canceled. + /// + /// Delivery of a timer event may be delayed by the system in order to improve power consumption + /// and system performance. The upper limit to the allowable delay may be configured with the `leeway` + /// argument; the lower limit is under the control of the system. + /// + /// For the initial timer fire at `deadline`, the upper limit to the allowable delay is set to + /// `leeway`. For the subsequent timer fires at `deadline + N * interval`, the upper + /// limit is the smaller of `leeway` and `interval/2`. + /// + /// The lower limit to the allowable delay may vary with process state such as visibility of the + /// application UI. If the timer source was created with flags `TimerFlags.strict`, the system + /// will make a best effort to strictly observe the provided `leeway` value, even if it is smaller + /// than the current lower limit. Note that a minimal amount of delay is to be expected even if + /// this flag is specified. + /// + /// Calling this method has no effect if the timer source has already been canceled. + /// + /// - parameter deadline: the time at which the timer event will be delivered, subject to the + /// leeway and other considerations described above. The deadline is based on Mach absolute + /// time. + /// - parameter interval: the interval for the timer. + /// - parameter leeway: the leeway for the timer. + /// + @available(swift, deprecated: 4, renamed: "schedule(deadline:repeating:leeway:)") public func scheduleRepeating(deadline: DispatchTime, interval: DispatchTimeInterval, leeway: DispatchTimeInterval = .nanoseconds(0)) { - __dispatch_source_set_timer(self as! DispatchSource, deadline.rawValue, UInt64(interval.rawValue), UInt64(leeway.rawValue)) + __dispatch_source_set_timer(self as! DispatchSource, deadline.rawValue, interval == .never ? ~0 : UInt64(interval.rawValue), UInt64(leeway.rawValue)) } + /// + /// Sets the deadline, interval and leeway for a timer event that fires at least once. + /// + /// Once this function returns, any pending source data accumulated for the previous timer values + /// has been cleared. The next timer event will occur at `deadline` and every `interval` seconds + /// thereafter until the timer source is canceled. + /// + /// Delivery of a timer event may be delayed by the system in order to improve power consumption and + /// system performance. The upper limit to the allowable delay may be configured with the `leeway` + /// argument; the lower limit is under the control of the system. + /// + /// For the initial timer fire at `deadline`, the upper limit to the allowable delay is set to + /// `leeway`. For the subsequent timer fires at `deadline + N * interval`, the upper + /// limit is the smaller of `leeway` and `interval/2`. + /// + /// The lower limit to the allowable delay may vary with process state such as visibility of the + /// application UI. If the timer source was created with flags `TimerFlags.strict`, the system + /// will make a best effort to strictly observe the provided `leeway` value, even if it is smaller + /// than the current lower limit. Note that a minimal amount of delay is to be expected even if + /// this flag is specified. + /// + /// Calling this method has no effect if the timer source has already been canceled. + /// + /// - parameter deadline: the time at which the timer event will be delivered, subject to the + /// leeway and other considerations described above. The deadline is based on Mach absolute + /// time. + /// - parameter interval: the interval for the timer in seconds. + /// - parameter leeway: the leeway for the timer. + /// + @available(swift, deprecated: 4, renamed: "schedule(deadline:repeating:leeway:)") public func scheduleRepeating(deadline: DispatchTime, interval: Double, leeway: DispatchTimeInterval = .nanoseconds(0)) { - __dispatch_source_set_timer(self as! DispatchSource, deadline.rawValue, UInt64(interval * Double(NSEC_PER_SEC)), UInt64(leeway.rawValue)) + __dispatch_source_set_timer(self as! DispatchSource, deadline.rawValue, interval.isInfinite ? ~0 : UInt64(interval * Double(NSEC_PER_SEC)), UInt64(leeway.rawValue)) } + /// + /// Sets the deadline, interval and leeway for a timer event that fires at least once. + /// + /// Once this function returns, any pending source data accumulated for the previous timer values + /// has been cleared. The next timer event will occur at `wallDeadline` and every `interval` units of + /// time thereafter until the timer source is canceled. + /// + /// Delivery of a timer event may be delayed by the system in order to improve power consumption and + /// system performance. The upper limit to the allowable delay may be configured with the `leeway` + /// argument; the lower limit is under the control of the system. + /// + /// For the initial timer fire at `wallDeadline`, the upper limit to the allowable delay is set to + /// `leeway`. For the subsequent timer fires at `wallDeadline + N * interval`, the upper + /// limit is the smaller of `leeway` and `interval/2`. + /// + /// The lower limit to the allowable delay may vary with process state such as visibility of the + /// application UI. If the timer source was created with flags `TimerFlags.strict`, the system + /// will make a best effort to strictly observe the provided `leeway` value, even if it is smaller + /// than the current lower limit. Note that a minimal amount of delay is to be expected even if + /// this flag is specified. + /// + /// Calling this method has no effect if the timer source has already been canceled. + /// + /// - parameter wallDeadline: the time at which the timer event will be delivered, subject to the + /// leeway and other considerations described above. The deadline is based on + /// `gettimeofday(3)`. + /// - parameter interval: the interval for the timer. + /// - parameter leeway: the leeway for the timer. + /// + @available(swift, deprecated: 4, renamed: "schedule(wallDeadline:repeating:leeway:)") public func scheduleRepeating(wallDeadline: DispatchWallTime, interval: DispatchTimeInterval, leeway: DispatchTimeInterval = .nanoseconds(0)) { - __dispatch_source_set_timer(self as! DispatchSource, wallDeadline.rawValue, UInt64(interval.rawValue), UInt64(leeway.rawValue)) + __dispatch_source_set_timer(self as! DispatchSource, wallDeadline.rawValue, interval == .never ? ~0 : UInt64(interval.rawValue), UInt64(leeway.rawValue)) } + /// + /// Sets the deadline, interval and leeway for a timer event that fires at least once. + /// + /// Once this function returns, any pending source data accumulated for the previous timer values + /// has been cleared. The next timer event will occur at `wallDeadline` and every `interval` seconds + /// thereafter until the timer source is canceled. + /// + /// Delivery of a timer event may be delayed by the system in order to improve power consumption and + /// system performance. The upper limit to the allowable delay may be configured with the `leeway` + /// argument; the lower limit is under the control of the system. + /// + /// For the initial timer fire at `wallDeadline`, the upper limit to the allowable delay is set to + /// `leeway`. For the subsequent timer fires at `wallDeadline + N * interval`, the upper + /// limit is the smaller of `leeway` and `interval/2`. + /// + /// The lower limit to the allowable delay may vary with process state such as visibility of the + /// application UI. If the timer source was created with flags `TimerFlags.strict`, the system + /// will make a best effort to strictly observe the provided `leeway` value, even if it is smaller + /// than the current lower limit. Note that a minimal amount of delay is to be expected even if + /// this flag is specified. + /// + /// Calling this method has no effect if the timer source has already been canceled. + /// + /// - parameter wallDeadline: the time at which the timer event will be delivered, subject to the + /// leeway and other considerations described above. The deadline is based on + /// `gettimeofday(3)`. + /// - parameter interval: the interval for the timer in seconds. + /// - parameter leeway: the leeway for the timer. + /// + @available(swift, deprecated: 4, renamed: "schedule(wallDeadline:repeating:leeway:)") public func scheduleRepeating(wallDeadline: DispatchWallTime, interval: Double, leeway: DispatchTimeInterval = .nanoseconds(0)) { - __dispatch_source_set_timer(self as! DispatchSource, wallDeadline.rawValue, UInt64(interval * Double(NSEC_PER_SEC)), UInt64(leeway.rawValue)) + __dispatch_source_set_timer(self as! DispatchSource, wallDeadline.rawValue, interval.isInfinite ? ~0 : UInt64(interval * Double(NSEC_PER_SEC)), UInt64(leeway.rawValue)) + } + + /// + /// Sets the deadline, repeat interval and leeway for a timer event. + /// + /// Once this function returns, any pending source data accumulated for the previous timer values + /// has been cleared. The next timer event will occur at `deadline` and every `repeating` units of + /// time thereafter until the timer source is canceled. If the value of `repeating` is `.never`, + /// or is defaulted, the timer fires only once. + /// + /// Delivery of a timer event may be delayed by the system in order to improve power consumption + /// and system performance. The upper limit to the allowable delay may be configured with the `leeway` + /// argument; the lower limit is under the control of the system. + /// + /// For the initial timer fire at `deadline`, the upper limit to the allowable delay is set to + /// `leeway`. For the subsequent timer fires at `deadline + N * repeating`, the upper + /// limit is the smaller of `leeway` and `repeating/2`. + /// + /// The lower limit to the allowable delay may vary with process state such as visibility of the + /// application UI. If the timer source was created with flags `TimerFlags.strict`, the system + /// will make a best effort to strictly observe the provided `leeway` value, even if it is smaller + /// than the current lower limit. Note that a minimal amount of delay is to be expected even if + /// this flag is specified. + /// + /// Calling this method has no effect if the timer source has already been canceled. + /// + /// - parameter deadline: the time at which the first timer event will be delivered, subject to the + /// leeway and other considerations described above. The deadline is based on Mach absolute + /// time. + /// - parameter repeating: the repeat interval for the timer, or `.never` if the timer should fire + /// only once. + /// - parameter leeway: the leeway for the timer. + /// + @available(swift, introduced: 4) + public func schedule(deadline: DispatchTime, repeating interval: DispatchTimeInterval = .never, leeway: DispatchTimeInterval = .nanoseconds(0)) { + __dispatch_source_set_timer(self as! DispatchSource, deadline.rawValue, interval == .never ? ~0 : UInt64(interval.rawValue), UInt64(leeway.rawValue)) + } + + /// + /// Sets the deadline, repeat interval and leeway for a timer event. + /// + /// Once this function returns, any pending source data accumulated for the previous timer values + /// has been cleared. The next timer event will occur at `deadline` and every `repeating` seconds + /// thereafter until the timer source is canceled. If the value of `repeating` is `.infinity`, + /// the timer fires only once. + /// + /// Delivery of a timer event may be delayed by the system in order to improve power consumption + /// and system performance. The upper limit to the allowable delay may be configured with the `leeway` + /// argument; the lower limit is under the control of the system. + /// + /// For the initial timer fire at `deadline`, the upper limit to the allowable delay is set to + /// `leeway`. For the subsequent timer fires at `deadline + N * repeating`, the upper + /// limit is the smaller of `leeway` and `repeating/2`. + /// + /// The lower limit to the allowable delay may vary with process state such as visibility of the + /// application UI. If the timer source was created with flags `TimerFlags.strict`, the system + /// will make a best effort to strictly observe the provided `leeway` value, even if it is smaller + /// than the current lower limit. Note that a minimal amount of delay is to be expected even if + /// this flag is specified. + /// + /// Calling this method has no effect if the timer source has already been canceled. + /// + /// - parameter deadline: the time at which the timer event will be delivered, subject to the + /// leeway and other considerations described above. The deadline is based on Mach absolute + /// time. + /// - parameter repeating: the repeat interval for the timer in seconds, or `.infinity` if the timer + /// should fire only once. + /// - parameter leeway: the leeway for the timer. + /// + @available(swift, introduced: 4) + public func schedule(deadline: DispatchTime, repeating interval: Double, leeway: DispatchTimeInterval = .nanoseconds(0)) { + __dispatch_source_set_timer(self as! DispatchSource, deadline.rawValue, interval.isInfinite ? ~0 : UInt64(interval * Double(NSEC_PER_SEC)), UInt64(leeway.rawValue)) + } + + /// + /// Sets the deadline, repeat interval and leeway for a timer event. + /// + /// Once this function returns, any pending source data accumulated for the previous timer values + /// has been cleared. The next timer event will occur at `wallDeadline` and every `repeating` units of + /// time thereafter until the timer source is canceled. If the value of `repeating` is `.never`, + /// or is defaulted, the timer fires only once. + /// + /// Delivery of a timer event may be delayed by the system in order to improve power consumption and + /// system performance. The upper limit to the allowable delay may be configured with the `leeway` + /// argument; the lower limit is under the control of the system. + /// + /// For the initial timer fire at `wallDeadline`, the upper limit to the allowable delay is set to + /// `leeway`. For the subsequent timer fires at `wallDeadline + N * repeating`, the upper + /// limit is the smaller of `leeway` and `repeating/2`. + /// + /// The lower limit to the allowable delay may vary with process state such as visibility of the + /// application UI. If the timer source was created with flags `TimerFlags.strict`, the system + /// will make a best effort to strictly observe the provided `leeway` value, even if it is smaller + /// than the current lower limit. Note that a minimal amount of delay is to be expected even if + /// this flag is specified. + /// + /// Calling this method has no effect if the timer source has already been canceled. + /// + /// - parameter wallDeadline: the time at which the timer event will be delivered, subject to the + /// leeway and other considerations described above. The deadline is based on + /// `gettimeofday(3)`. + /// - parameter repeating: the repeat interval for the timer, or `.never` if the timer should fire + /// only once. + /// - parameter leeway: the leeway for the timer. + /// + @available(swift, introduced: 4) + public func schedule(wallDeadline: DispatchWallTime, repeating interval: DispatchTimeInterval = .never, leeway: DispatchTimeInterval = .nanoseconds(0)) { + __dispatch_source_set_timer(self as! DispatchSource, wallDeadline.rawValue, interval == .never ? ~0 : UInt64(interval.rawValue), UInt64(leeway.rawValue)) + } + + /// + /// Sets the deadline, repeat interval and leeway for a timer event that fires at least once. + /// + /// Once this function returns, any pending source data accumulated for the previous timer values + /// has been cleared. The next timer event will occur at `wallDeadline` and every `repeating` seconds + /// thereafter until the timer source is canceled. If the value of `repeating` is `.infinity`, + /// the timer fires only once. + /// + /// Delivery of a timer event may be delayed by the system in order to improve power consumption + /// and system performance. The upper limit to the allowable delay may be configured with the `leeway` + /// argument; the lower limit is under the control of the system. + /// + /// For the initial timer fire at `wallDeadline`, the upper limit to the allowable delay is set to + /// `leeway`. For the subsequent timer fires at `wallDeadline + N * repeating`, the upper + /// limit is the smaller of `leeway` and `repeating/2`. + /// + /// The lower limit to the allowable delay may vary with process state such as visibility of the + /// application UI. If the timer source was created with flags `TimerFlags.strict`, the system + /// will make a best effort to strictly observe the provided `leeway` value, even if it is smaller + /// than the current lower limit. Note that a minimal amount of delay is to be expected even if + /// this flag is specified. + /// + /// Calling this method has no effect if the timer source has already been canceled. + /// + /// - parameter wallDeadline: the time at which the timer event will be delivered, subject to the + /// leeway and other considerations described above. The deadline is based on + /// `gettimeofday(3)`. + /// - parameter repeating: the repeat interval for the timer in secondss, or `.infinity` if the timer + /// should fire only once. + /// - parameter leeway: the leeway for the timer. + /// + @available(swift, introduced: 4) + public func schedule(wallDeadline: DispatchWallTime, repeating interval: Double, leeway: DispatchTimeInterval = .nanoseconds(0)) { + __dispatch_source_set_timer(self as! DispatchSource, wallDeadline.rawValue, interval.isInfinite ? ~0 : UInt64(interval * Double(NSEC_PER_SEC)), UInt64(leeway.rawValue)) } } diff --git a/stdlib/public/SDK/Dispatch/Time.swift b/stdlib/public/SDK/Dispatch/Time.swift index ecfb1b487dc..3459d55284a 100644 --- a/stdlib/public/SDK/Dispatch/Time.swift +++ b/stdlib/public/SDK/Dispatch/Time.swift @@ -114,11 +114,13 @@ extension DispatchWallTime { } } -public enum DispatchTimeInterval { +public enum DispatchTimeInterval : Equatable { case seconds(Int) case milliseconds(Int) case microseconds(Int) case nanoseconds(Int) + @_downgrade_exhaustivity_check + case never internal var rawValue: Int64 { switch self { @@ -126,6 +128,16 @@ public enum DispatchTimeInterval { case .milliseconds(let ms): return Int64(ms) * Int64(NSEC_PER_MSEC) case .microseconds(let us): return Int64(us) * Int64(NSEC_PER_USEC) case .nanoseconds(let ns): return Int64(ns) + case .never: return Int64.max + } + } + + public static func ==(lhs: DispatchTimeInterval, rhs: DispatchTimeInterval) -> Bool { + switch (lhs, rhs) { + case (.never, .never): return true + case (.never, _): return false + case (_, .never): return false + default: return lhs.rawValue == rhs.rawValue } } } diff --git a/stdlib/public/SDK/Foundation/CheckClass.mm b/stdlib/public/SDK/Foundation/CheckClass.mm index 5171dadcd8d..f3af9e8d615 100644 --- a/stdlib/public/SDK/Foundation/CheckClass.mm +++ b/stdlib/public/SDK/Foundation/CheckClass.mm @@ -2,6 +2,7 @@ #include +#include "swift/Runtime/HeapObject.h" #include "swift/Runtime/Metadata.h" @interface NSKeyedUnarchiver (SwiftAdditions) @@ -10,9 +11,117 @@ NS_SWIFT_NAME(_swift_checkClassAndWarnForKeyedArchiving(_:operation:)); @end +static bool isASCIIIdentifierChar(char c) { + if (c >= 'a' && c <= 'z') return true; + if (c >= 'A' && c <= 'Z') return true; + if (c >= '0' && c <= '9') return true; + if (c == '_') return true; + if (c == '$') return true; + return false; +} + +static void logIfFirstOccurrence(Class objcClass, void (^log)(void)) { + static auto queue = dispatch_queue_create( + "SwiftFoundation._checkClassAndWarnForKeyedArchivingQueue", + DISPATCH_QUEUE_SERIAL); + static NSHashTable *seenClasses = nil; + + dispatch_sync(queue, ^{ + // Will be NO when seenClasses is still nil. + if ([seenClasses containsObject:objcClass]) + return; + + if (!seenClasses) { + NSPointerFunctionsOptions options = 0; + options |= NSPointerFunctionsOpaqueMemory; + options |= NSPointerFunctionsObjectPointerPersonality; + seenClasses = [[NSHashTable alloc] initWithOptions:options capacity:16]; + } + [seenClasses addObject:objcClass]; + + // Synchronize logging so that multiple lines aren't interleaved. + log(); + }); +} + +namespace { + class StringRefLite { + StringRefLite(const char *data, size_t len) : data(data), length(len) {} + public: + const char *data; + size_t length; + + StringRefLite() : data(nullptr), length(0) {} + + template + StringRefLite(const char (&staticStr)[N]) : data(staticStr), length(N) {} + + StringRefLite(swift::TwoWordPair::Return rawValue) + : data(swift::TwoWordPair(rawValue).first), + length(swift::TwoWordPair(rawValue).second){} + + NS_RETURNS_RETAINED + NSString *newNSStringNoCopy() const { + return [[NSString alloc] initWithBytesNoCopy:const_cast(data) + length:length + encoding:NSUTF8StringEncoding + freeWhenDone:NO]; + } + + const char &operator[](size_t offset) const { + assert(offset < length); + return data[offset]; + } + + StringRefLite slice(size_t from, size_t to) const { + assert(from <= to); + assert(to <= length); + return {data + from, to - from}; + } + + const char *begin() const { + return data; + } + const char *end() const { + return data + length; + } + }; +} + +/// Assume that a non-generic demangled class name always ends in ".MyClass" +/// or ".(MyClass plus extra info)". +static StringRefLite findBaseName(StringRefLite demangledName) { + size_t end = demangledName.length; + size_t parenCount = 0; + for (size_t i = end; i != 0; --i) { + switch (demangledName[i - 1]) { + case '.': + if (parenCount == 0) { + if (i != end && demangledName[i] == '(') + ++i; + return demangledName.slice(i, end); + } + break; + case ')': + parenCount += 1; + break; + case '(': + if (parenCount > 0) + parenCount -= 1; + break; + case ' ': + end = i - 1; + break; + default: + break; + } + } + return {}; +} + @implementation NSKeyedUnarchiver (SwiftAdditions) -/// Checks if class \p cls is good for archiving. +/// Checks if class \p objcClass is good for archiving. /// /// If not, a runtime warning is printed. /// @@ -25,20 +134,21 @@ /// 2: a Swift non-generic class where adding @objc is valid /// Future versions of this API will return nonzero values for additional cases /// that mean the class shouldn't be archived. -+ (int)_swift_checkClassAndWarnForKeyedArchiving:(Class)cls ++ (int)_swift_checkClassAndWarnForKeyedArchiving:(Class)objcClass operation:(int)operation { - const swift::ClassMetadata *theClass = (swift::ClassMetadata *)cls; + using namespace swift; + const ClassMetadata *theClass = (ClassMetadata *)objcClass; // Is it a (real) swift class? if (!theClass->isTypeMetadata() || theClass->isArtificialSubclass()) return 0; // Does the class already have a custom name? - if (theClass->getFlags() & swift::ClassFlags::HasCustomObjCName) + if (theClass->getFlags() & ClassFlags::HasCustomObjCName) return 0; // Is it a mangled name? - const char *className = class_getName(cls); + const char *className = class_getName(objcClass); if (!(className[0] == '_' && className[1] == 'T')) return 0; // Is it a name in the form .? Note: the module name could @@ -48,13 +158,74 @@ // Is it a generic class? if (theClass->getDescription()->GenericParams.isGeneric()) { - // TODO: print a warning + logIfFirstOccurrence(objcClass, ^{ + // Use actual NSStrings to force UTF-8. + StringRefLite demangledName = swift_getTypeName(theClass, + /*qualified*/true); + NSString *demangledString = demangledName.newNSStringNoCopy(); + NSString *mangledString = NSStringFromClass(objcClass); + switch (operation) { + case 1: + NSLog(@"Attempting to unarchive generic Swift class '%@' with mangled " + "runtime name '%@'. Runtime names for generic classes are " + "unstable and may change in the future, leading to " + "non-decodable data.", demangledString, mangledString); + break; + default: + NSLog(@"Attempting to archive generic Swift class '%@' with mangled " + "runtime name '%@'. Runtime names for generic classes are " + "unstable and may change in the future, leading to " + "non-decodable data.", demangledString, mangledString); + break; + } + NSLog(@"To avoid this failure, create a concrete subclass and register " + "it with NSKeyedUnarchiver.setClass(_:forClassName:) instead, " + "using the name \"%@\".", mangledString); + NSLog(@"If you need to produce archives compatible with older versions " + "of your program, use NSKeyedArchiver.setClassName(_:for:) " + "as well."); + [demangledString release]; + }); return 1; } // It's a swift class with a (compiler generated) mangled name, which should // be written into an NSArchive. - // TODO: print a warning + logIfFirstOccurrence(objcClass, ^{ + // Use actual NSStrings to force UTF-8. + StringRefLite demangledName = swift_getTypeName(theClass,/*qualified*/true); + NSString *demangledString = demangledName.newNSStringNoCopy(); + NSString *mangledString = NSStringFromClass(objcClass); + switch (operation) { + case 1: + NSLog(@"Attempting to unarchive Swift class '%@' with mangled runtime " + "name '%@'. The runtime name for this class is unstable and may " + "change in the future, leading to non-decodable data.", + demangledString, mangledString); + break; + default: + NSLog(@"Attempting to archive Swift class '%@' with mangled runtime " + "name '%@'. The runtime name for this class is unstable and may " + "change in the future, leading to non-decodable data.", + demangledString, mangledString); + break; + } + [demangledString release]; + NSLog(@"You can use the 'objc' attribute to ensure that the name will not " + "change: \"@objc(%@)\"", mangledString); + + StringRefLite baseName = findBaseName(demangledName); + // Offer a more generic message if the base name we found doesn't look like + // an ASCII identifier. This avoids printing names like "ABCモデル". + if (baseName.length == 0 || + !std::all_of(baseName.begin(), baseName.end(), isASCIIIdentifierChar)) { + baseName = "MyModel"; + } + + NSLog(@"If there are no existing archives containing this class, you " + "should choose a unique, prefixed name instead: " + "\"@objc(ABC%1$.*2$s)\"", baseName.data, (int)baseName.length); + }); return 2; } @end diff --git a/stdlib/public/SDK/Foundation/Data.swift b/stdlib/public/SDK/Foundation/Data.swift index 702c8c14d83..6c953b3921c 100644 --- a/stdlib/public/SDK/Foundation/Data.swift +++ b/stdlib/public/SDK/Foundation/Data.swift @@ -319,6 +319,7 @@ public final class _DataStorage { @inline(__always) public func append(_ bytes: UnsafeRawPointer, length: Int) { + precondition(length >= 0, "Length of appending bytes must be positive") switch _backing { case .swift: let origLength = _length @@ -350,11 +351,11 @@ public final class _DataStorage { // fast-path for appending directly from another data storage @inline(__always) - public func append(_ otherData: _DataStorage, startingAt start: Int) { + public func append(_ otherData: _DataStorage, startingAt start: Int, endingAt end: Int) { let otherLength = otherData.length if otherLength == 0 { return } if let bytes = otherData.bytes { - append(bytes.advanced(by: start), length: otherLength) + append(bytes.advanced(by: start), length: end - start) } } @@ -1087,6 +1088,20 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl _sliceRange = range } + @_versioned + internal func _validateIndex(_ index: Int, message: String? = nil) { + precondition(_sliceRange.contains(index), message ?? "Index \(index) is out of bounds of range \(_sliceRange)") + } + + @_versioned + internal func _validateRange(_ range: R) where R.Bound == Int { + let lower = R.Bound(_sliceRange.lowerBound) + let upper = R.Bound(_sliceRange.upperBound) + let r = range.relative(to: lower..= _sliceRange.lowerBound && r.lowerBound <= _sliceRange.upperBound, "Range \(r) is out of bounds of range \(_sliceRange)") + precondition(r.upperBound >= _sliceRange.lowerBound && r.upperBound <= _sliceRange.upperBound, "Range \(r) is out of bounds of range \(_sliceRange)") + } + // ----------------------------------- // MARK: - Properties and Functions @@ -1099,6 +1114,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl } @inline(__always) set { + precondition(count >= 0, "count must be positive") if !isKnownUniquelyReferenced(&_backing) { _backing = _backing.mutableCopy(_sliceRange) } @@ -1142,14 +1158,15 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl /// - warning: This method does not verify that the contents at pointer have enough space to hold `count` bytes. @inline(__always) public func copyBytes(to pointer: UnsafeMutablePointer, count: Int) { + precondition(count >= 0, "count of bytes to copy must be positive") if count == 0 { return } - memcpy(UnsafeMutableRawPointer(pointer), _backing.bytes!.advanced(by: _sliceRange.lowerBound), count) + memcpy(UnsafeMutableRawPointer(pointer), _backing.bytes!.advanced(by: _sliceRange.lowerBound), Swift.min(count, _sliceRange.count)) } @inline(__always) private func _copyBytesHelper(to pointer: UnsafeMutableRawPointer, from range: NSRange) { if range.length == 0 { return } - memcpy(UnsafeMutableRawPointer(pointer), _backing.bytes!.advanced(by: range.location), range.length) + memcpy(UnsafeMutableRawPointer(pointer), _backing.bytes!.advanced(by: range.location), Swift.min(range.length, _sliceRange.count)) } /// Copy a subset of the contents of the data to a pointer. @@ -1175,16 +1192,11 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl let copyRange : Range if let r = range { guard !r.isEmpty else { return 0 } - precondition(r.lowerBound >= 0) - precondition(r.lowerBound < cnt, "The range is outside the bounds of the data") - - precondition(r.upperBound >= 0) - precondition(r.upperBound <= cnt, "The range is outside the bounds of the data") - copyRange = r.lowerBound..<(r.lowerBound + Swift.min(buffer.count * MemoryLayout.stride, r.count)) } else { copyRange = 0...stride, cnt) } + _validateRange(copyRange) guard !copyRange.isEmpty else { return 0 } @@ -1243,6 +1255,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl public func range(of dataToFind: Data, options: Data.SearchOptions = [], in range: Range? = nil) -> Range? { let nsRange : NSRange if let r = range { + _validateRange(r) nsRange = NSMakeRange(r.lowerBound, r.upperBound - r.lowerBound) } else { nsRange = NSMakeRange(0, _backing.length) @@ -1266,6 +1279,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl @inline(__always) public mutating func append(_ bytes: UnsafePointer, count: Int) { + precondition(count >= 0, "count must be positive") if count == 0 { return } if !isKnownUniquelyReferenced(&_backing) { _backing = _backing.mutableCopy(_sliceRange) @@ -1279,7 +1293,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl if !isKnownUniquelyReferenced(&_backing) { _backing = _backing.mutableCopy(_sliceRange) } - _backing.append(other._backing, startingAt: other._sliceRange.lowerBound) + _backing.append(other._backing, startingAt: other._sliceRange.lowerBound, endingAt: other._sliceRange.upperBound) _sliceRange = _sliceRange.lowerBound..<(_sliceRange.upperBound + other.count) } @@ -1326,6 +1340,9 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl /// - parameter range: The range in the data to set to `0`. @inline(__always) public mutating func resetBytes(in range: Range) { + // it is worth noting that the range here may be out of bounds of the Data itself (which triggers a growth) + precondition(range.lowerBound >= 0, "Ranges must be positive bounds") + precondition(range.upperBound >= 0, "Ranges must be positive bounds") let range = NSMakeRange(range.lowerBound, range.upperBound - range.lowerBound) if !isKnownUniquelyReferenced(&_backing) { _backing = _backing.mutableCopy(_sliceRange) @@ -1346,6 +1363,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl /// - parameter data: The replacement data. @inline(__always) public mutating func replaceSubrange(_ subrange: Range, with data: Data) { + _validateRange(subrange) let nsRange = NSMakeRange(subrange.lowerBound, subrange.upperBound - subrange.lowerBound) let cnt = data.count if !isKnownUniquelyReferenced(&_backing) { @@ -1361,6 +1379,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl @inline(__always) public mutating func replaceSubrange(_ subrange: CountableRange, with data: Data) { + _validateRange(subrange) let nsRange = NSMakeRange(subrange.lowerBound, subrange.upperBound - subrange.lowerBound) let cnt = data.count if !isKnownUniquelyReferenced(&_backing) { @@ -1383,6 +1402,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl /// - parameter buffer: The replacement bytes. @inline(__always) public mutating func replaceSubrange(_ subrange: Range, with buffer: UnsafeBufferPointer) { + _validateRange(subrange) let nsRange = NSMakeRange(subrange.lowerBound, subrange.upperBound - subrange.lowerBound) let bufferCount = buffer.count * MemoryLayout.stride @@ -1405,19 +1425,13 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl @inline(__always) public mutating func replaceSubrange(_ subrange: Range, with newElements: ByteCollection) where ByteCollection.Iterator.Element == Data.Iterator.Element { - + _validateRange(subrange) // Calculate this once, it may not be O(1) let replacementCount: Int = numericCast(newElements.count) let currentCount = self.count let subrangeCount = subrange.count - if currentCount < subrange.lowerBound + subrangeCount { - if subrangeCount == 0 { - preconditionFailure("location \(subrange.lowerBound) exceeds data count \(currentCount)") - } else { - preconditionFailure("range \(subrange) exceeds data count \(currentCount)") - } - } + _validateRange(subrange) let resultCount = currentCount - subrangeCount + replacementCount if resultCount != currentCount { @@ -1446,6 +1460,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl @inline(__always) public mutating func replaceSubrange(_ subrange: Range, with bytes: UnsafeRawPointer, count cnt: Int) { + _validateRange(subrange) let nsRange = NSMakeRange(subrange.lowerBound, subrange.upperBound - subrange.lowerBound) if !isKnownUniquelyReferenced(&_backing) { _backing = _backing.mutableCopy(_sliceRange) @@ -1461,11 +1476,11 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl /// - parameter range: The range to copy. @inline(__always) public func subdata(in range: Range) -> Data { + _validateRange(range) let length = count if count == 0 { return Data() } - precondition(length >= range.upperBound) return _backing.subdata(in: range) } @@ -1502,6 +1517,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl @inline(__always) public func advanced(by amount: Int) -> Data { + _validateIndex(startIndex + amount) let length = count - amount precondition(length > 0) return withUnsafeBytes { (ptr: UnsafePointer) -> Data in @@ -1518,10 +1534,12 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl public subscript(index: Index) -> UInt8 { @inline(__always) get { + _validateIndex(index) return _backing.bytes!.advanced(by: index).assumingMemoryBound(to: UInt8.self).pointee } @inline(__always) set { + _validateIndex(index) if !isKnownUniquelyReferenced(&_backing) { _backing = _backing.mutableCopy(_sliceRange) } @@ -1532,6 +1550,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl public subscript(bounds: Range) -> Data { @inline(__always) get { + _validateRange(bounds) return Data(backing: _backing, range: bounds) } @inline(__always) @@ -1544,19 +1563,27 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl where R.Bound: FixedWidthInteger, R.Bound.Stride : SignedInteger { @inline(__always) get { - let range = rangeExpression.relative(to: 0.. = start.. = start..(slice)) } diff --git a/stdlib/public/SDK/Foundation/JSONEncoder.swift b/stdlib/public/SDK/Foundation/JSONEncoder.swift index 786c2d01375..1751ae80909 100644 --- a/stdlib/public/SDK/Foundation/JSONEncoder.swift +++ b/stdlib/public/SDK/Foundation/JSONEncoder.swift @@ -122,7 +122,7 @@ open class JSONEncoder { /// /// - parameter value: The value to encode. /// - returns: A new `Data` value containing the encoded JSON data. - /// - throws: `EncodingError.invalidValue` if a non-comforming floating-point value is encountered during encoding, and the encoding strategy is `.throw`. + /// - throws: `EncodingError.invalidValue` if a non-conforming floating-point value is encountered during encoding, and the encoding strategy is `.throw`. /// - throws: An error if any value throws an error during encoding. open func encode(_ value: T) throws -> Data { let encoder = _JSONEncoder(options: self.options) @@ -141,7 +141,7 @@ open class JSONEncoder { throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: [], debugDescription: "Top-level \(T.self) encoded as string JSON fragment.")) } - var writingOptions = JSONSerialization.WritingOptions(rawValue: self.outputFormatting.rawValue) + let writingOptions = JSONSerialization.WritingOptions(rawValue: self.outputFormatting.rawValue) return try JSONSerialization.data(withJSONObject: topLevel, options: writingOptions) } } @@ -190,7 +190,7 @@ fileprivate class _JSONEncoder : Encoder { /// Returns whether a new element can be encoded at this coding path. /// /// `true` if an element has not yet been encoded at this coding path; `false` otherwise. - var canEncodeNewElement: Bool { + var canEncodeNewValue: Bool { // Every time a new value gets encoded, the key it's encoded for is pushed onto the coding path (even if it's a nil key from an unkeyed container). // At the same time, every time a container is requested, a new value gets pushed onto the storage stack. // If there are more values on the storage stack than on the coding path, it means the value is requesting more than one container, which violates the precondition. @@ -200,39 +200,43 @@ fileprivate class _JSONEncoder : Encoder { return self.storage.count == self.codingPath.count } - /// Asserts that a new container can be requested at this coding path. - /// `preconditionFailure()`s if one cannot be requested. - func assertCanRequestNewContainer() { - guard self.canEncodeNewElement else { - let previousContainerType: String - if self.storage.containers.last is NSDictionary { - previousContainerType = "keyed" - } else if self.storage.containers.last is NSArray { - previousContainerType = "unkeyed" - } else { - previousContainerType = "single value" - } - - preconditionFailure("Attempt to encode with new container when already encoded with \(previousContainerType) container.") - } - } - // MARK: - Encoder Methods func container(keyedBy: Key.Type) -> KeyedEncodingContainer { - assertCanRequestNewContainer() - let topContainer = self.storage.pushKeyedContainer() + // If an existing keyed container was already requested, return that one. + let topContainer: NSMutableDictionary + if self.canEncodeNewValue { + // We haven't yet pushed a container at this level; do so here. + topContainer = self.storage.pushKeyedContainer() + } else { + guard let container = self.storage.containers.last as? NSMutableDictionary else { + preconditionFailure("Attempt to push new keyed encoding container when already previously encoded at this path.") + } + + topContainer = container + } + let container = _JSONKeyedEncodingContainer(referencing: self, codingPath: self.codingPath, wrapping: topContainer) return KeyedEncodingContainer(container) } func unkeyedContainer() -> UnkeyedEncodingContainer { - assertCanRequestNewContainer() - let topContainer = self.storage.pushUnkeyedContainer() + // If an existing unkeyed container was already requested, return that one. + let topContainer: NSMutableArray + if self.canEncodeNewValue { + // We haven't yet pushed a container at this level; do so here. + topContainer = self.storage.pushUnkeyedContainer() + } else { + guard let container = self.storage.containers.last as? NSMutableArray else { + preconditionFailure("Attempt to push new unkeyed encoding container when already previously encoded at this path.") + } + + topContainer = container + } + return _JSONUnkeyedEncodingContainer(referencing: self, codingPath: self.codingPath, wrapping: topContainer) } func singleValueContainer() -> SingleValueEncodingContainer { - assertCanRequestNewContainer() return self } } @@ -474,106 +478,89 @@ fileprivate struct _JSONUnkeyedEncodingContainer : UnkeyedEncodingContainer { } extension _JSONEncoder : SingleValueEncodingContainer { - // MARK: - Utility Methods - - /// Asserts that a single value can be encoded at the current coding path (i.e. that one has not already been encoded through this container). - /// `preconditionFailure()`s if one cannot be encoded. - /// - /// This is similar to assertCanRequestNewContainer above. - func assertCanEncodeSingleValue() { - guard self.canEncodeNewElement else { - let previousContainerType: String - if self.storage.containers.last is NSDictionary { - previousContainerType = "keyed" - } else if self.storage.containers.last is NSArray { - previousContainerType = "unkeyed" - } else { - preconditionFailure("Attempt to encode multiple values in a single value container.") - } - - preconditionFailure("Attempt to encode with new container when already encoded with \(previousContainerType) container.") - } - } - // MARK: - SingleValueEncodingContainer Methods + func assertCanEncodeNewValue() { + precondition(self.canEncodeNewValue, "Attempt to encode value through single value container when previously value already encoded.") + } + func encodeNil() throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: NSNull()) } func encode(_ value: Bool) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: Int) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: Int8) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: Int16) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: Int32) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: Int64) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: UInt) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: UInt8) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: UInt16) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: UInt32) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: UInt64) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: String) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: Float) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() try self.storage.push(container: box(value)) } func encode(_ value: Double) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() try self.storage.push(container: box(value)) } func encode(_ value: T) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() try self.storage.push(container: box(value)) } } @@ -701,6 +688,9 @@ extension _JSONEncoder { } else if T.self == URL.self { // Encode URLs as single strings. return self.box((value as! URL).absoluteString) + } else if T.self == Decimal.self { + // JSONSerialization can natively handle NSDecimalNumber. + return (value as! Decimal) as NSDecimalNumber } // The value should request a container from the _JSONEncoder. @@ -763,7 +753,7 @@ fileprivate class _JSONReferencingEncoder : _JSONEncoder { // MARK: - Coding Path Operations - override var canEncodeNewElement: Bool { + override var canEncodeNewValue: Bool { // With a regular encoder, the storage and coding path grow together. // A referencing encoder, however, inherits its parents coding path, as well as the key it was created for. // We have to take this into account. @@ -1961,6 +1951,19 @@ extension _JSONDecoder { } } + func unbox(_ value: Any?, as type: Decimal.Type) throws -> Decimal? { + guard let value = value else { return nil } + guard !(value is NSNull) else { return nil } + + // Attempt to bridge from NSDecimalNumber. + if let decimal = value as? Decimal { + return decimal + } else { + let doubleValue = try self.unbox(value, as: Double.self)! + return Decimal(doubleValue) + } + } + func unbox(_ value: Any?, as type: T.Type) throws -> T? { guard let value = value else { return nil } guard !(value is NSNull) else { return nil } @@ -1981,6 +1984,8 @@ extension _JSONDecoder { } decoded = (url as! T) + } else if T.self == Decimal.self { + decoded = (try self.unbox(value, as: Decimal.self) as! T) } else { self.storage.push(container: value) decoded = try T(from: self) diff --git a/stdlib/public/SDK/Foundation/NSCoder.swift b/stdlib/public/SDK/Foundation/NSCoder.swift index d6d4b8f8ace..b973195f5b0 100644 --- a/stdlib/public/SDK/Foundation/NSCoder.swift +++ b/stdlib/public/SDK/Foundation/NSCoder.swift @@ -147,9 +147,9 @@ extension NSKeyedUnarchiver { @nonobjc @available(swift, introduced: 4) @available(OSX 10.11, iOS 9.0, *) - public class func unarchiveTopLevelObjectWithData(_ data: NSData) throws -> Any? { + public class func unarchiveTopLevelObjectWithData(_ data: Data) throws -> Any? { var error: NSError? - let result = __NSKeyedUnarchiverUnarchiveObject(self, data, &error) + let result = __NSKeyedUnarchiverUnarchiveObject(self, data as NSData, &error) try resolveError(error) return result } diff --git a/stdlib/public/SDK/Foundation/NSError.swift b/stdlib/public/SDK/Foundation/NSError.swift index 939b9d2b24b..768fb267003 100644 --- a/stdlib/public/SDK/Foundation/NSError.swift +++ b/stdlib/public/SDK/Foundation/NSError.swift @@ -602,7 +602,7 @@ public struct CocoaError : _BridgedStoredNSError { public static var _nsErrorDomain: String { return NSCocoaErrorDomain } /// The error code itself. - public struct Code : RawRepresentable, _ErrorCodeProtocol { + public struct Code : RawRepresentable, Hashable, _ErrorCodeProtocol { public typealias _ErrorType = CocoaError public let rawValue: Int @@ -610,6 +610,10 @@ public struct CocoaError : _BridgedStoredNSError { public init(rawValue: Int) { self.rawValue = rawValue } + + public var hashValue: Int { + return self.rawValue + } } } @@ -1845,7 +1849,7 @@ public struct URLError : _BridgedStoredNSError { public static var _nsErrorDomain: String { return NSURLErrorDomain } /// The error code itself. - public struct Code : RawRepresentable, _ErrorCodeProtocol { + public struct Code : RawRepresentable, Hashable, _ErrorCodeProtocol { public typealias _ErrorType = URLError public let rawValue: Int @@ -1853,6 +1857,10 @@ public struct URLError : _BridgedStoredNSError { public init(rawValue: Int) { self.rawValue = rawValue } + + public var hashValue: Int { + return self.rawValue + } } } diff --git a/stdlib/public/SDK/Foundation/NSNumber.swift b/stdlib/public/SDK/Foundation/NSNumber.swift index b436850ae3b..9202604fbaa 100644 --- a/stdlib/public/SDK/Foundation/NSNumber.swift +++ b/stdlib/public/SDK/Foundation/NSNumber.swift @@ -14,7 +14,7 @@ import CoreGraphics extension Int8 : _ObjectiveCBridgeable { - @available(swift, deprecated: 4) + @available(swift, deprecated: 4, renamed: "init(truncating:)") public init(_ number: NSNumber) { self = number.int8Value } @@ -55,7 +55,7 @@ extension Int8 : _ObjectiveCBridgeable { } extension UInt8 : _ObjectiveCBridgeable { - @available(swift, deprecated: 4) + @available(swift, deprecated: 4, renamed: "init(truncating:)") public init(_ number: NSNumber) { self = number.uint8Value } @@ -96,7 +96,7 @@ extension UInt8 : _ObjectiveCBridgeable { } extension Int16 : _ObjectiveCBridgeable { - @available(swift, deprecated: 4) + @available(swift, deprecated: 4, renamed: "init(truncating:)") public init(_ number: NSNumber) { self = number.int16Value } @@ -137,7 +137,7 @@ extension Int16 : _ObjectiveCBridgeable { } extension UInt16 : _ObjectiveCBridgeable { - @available(swift, deprecated: 4) + @available(swift, deprecated: 4, renamed: "init(truncating:)") public init(_ number: NSNumber) { self = number.uint16Value } @@ -178,7 +178,7 @@ extension UInt16 : _ObjectiveCBridgeable { } extension Int32 : _ObjectiveCBridgeable { - @available(swift, deprecated: 4) + @available(swift, deprecated: 4, renamed: "init(truncating:)") public init(_ number: NSNumber) { self = number.int32Value } @@ -219,7 +219,7 @@ extension Int32 : _ObjectiveCBridgeable { } extension UInt32 : _ObjectiveCBridgeable { - @available(swift, deprecated: 4) + @available(swift, deprecated: 4, renamed: "init(truncating:)") public init(_ number: NSNumber) { self = number.uint32Value } @@ -260,7 +260,7 @@ extension UInt32 : _ObjectiveCBridgeable { } extension Int64 : _ObjectiveCBridgeable { - @available(swift, deprecated: 4) + @available(swift, deprecated: 4, renamed: "init(truncating:)") public init(_ number: NSNumber) { self = number.int64Value } @@ -301,7 +301,7 @@ extension Int64 : _ObjectiveCBridgeable { } extension UInt64 : _ObjectiveCBridgeable { - @available(swift, deprecated: 4) + @available(swift, deprecated: 4, renamed: "init(truncating:)") public init(_ number: NSNumber) { self = number.uint64Value } @@ -342,7 +342,7 @@ extension UInt64 : _ObjectiveCBridgeable { } extension Int : _ObjectiveCBridgeable { - @available(swift, deprecated: 4) + @available(swift, deprecated: 4, renamed: "init(truncating:)") public init(_ number: NSNumber) { self = number.intValue } @@ -383,7 +383,7 @@ extension Int : _ObjectiveCBridgeable { } extension UInt : _ObjectiveCBridgeable { - @available(swift, deprecated: 4) + @available(swift, deprecated: 4, renamed: "init(truncating:)") public init(_ number: NSNumber) { self = number.uintValue } @@ -424,7 +424,7 @@ extension UInt : _ObjectiveCBridgeable { } extension Float : _ObjectiveCBridgeable { - @available(swift, deprecated: 4) + @available(swift, deprecated: 4, renamed: "init(truncating:)") public init(_ number: NSNumber) { self = number.floatValue } @@ -451,8 +451,24 @@ extension Float : _ObjectiveCBridgeable { } public static func _conditionallyBridgeFromObjectiveC(_ x: NSNumber, result: inout Float?) -> Bool { - guard let value = Float(exactly: x) else { return false } - result = value + guard let value = Double(exactly: x) else { return false } + guard !value.isNaN else { + result = Float.nan + return true + } + guard !value.isInfinite else { + if value.sign == .minus { + result = -Float.infinity + } else { + result = Float.infinity + } + return true + } + guard Swift.abs(value) <= Double(Float.greatestFiniteMagnitude) else { + return false + } + + result = Float(value) return true } @@ -465,7 +481,7 @@ extension Float : _ObjectiveCBridgeable { } extension Double : _ObjectiveCBridgeable { - @available(swift, deprecated: 4) + @available(swift, deprecated: 4, renamed: "init(truncating:)") public init(_ number: NSNumber) { self = number.doubleValue } @@ -513,7 +529,7 @@ extension Double : _ObjectiveCBridgeable { } extension Bool : _ObjectiveCBridgeable { - @available(swift, deprecated: 4) + @available(swift, deprecated: 4, renamed: "init(truncating:)") public init(_ number: NSNumber) { self = number.boolValue } @@ -564,7 +580,7 @@ extension Bool : _ObjectiveCBridgeable { } extension CGFloat : _ObjectiveCBridgeable { - @available(swift, deprecated: 4) + @available(swift, deprecated: 4, renamed: "init(truncating:)") public init(_ number: NSNumber) { native = CGFloat.NativeType(truncating: number) } diff --git a/stdlib/public/SDK/Foundation/NSRange.swift b/stdlib/public/SDK/Foundation/NSRange.swift index 2adf2da6139..1342d5c4b63 100644 --- a/stdlib/public/SDK/Foundation/NSRange.swift +++ b/stdlib/public/SDK/Foundation/NSRange.swift @@ -22,17 +22,23 @@ extension NSRange : Hashable { } public static func==(_ lhs: NSRange, _ rhs: NSRange) -> Bool { - return lhs.location == rhs.location && rhs.length == rhs.length + return lhs.location == rhs.location && lhs.length == rhs.length } } extension NSRange : CustomStringConvertible, CustomDebugStringConvertible { public var description: String { return "{\(location), \(length)}" } - public var debugDescription: String { return "{\(location), \(length)}" } + public var debugDescription: String { + guard location != NSNotFound else { + return "{NSNotFound, \(length)}" + } + return "{\(location), \(length)}" + } } extension NSRange { public init?(_ string: String) { + var savedLocation = 0 if string.isEmpty { // fail early if the string is empty return nil @@ -45,6 +51,7 @@ extension NSRange { return nil } var location = 0 + savedLocation = scanner.scanLocation guard scanner.scanInt(&location) else { return nil } @@ -52,16 +59,44 @@ extension NSRange { // return early if there are no more characters after the first int in the string return nil } + if scanner.scanString(".", into: nil) { + scanner.scanLocation = savedLocation + var double = 0.0 + guard scanner.scanDouble(&double) else { + return nil + } + guard let integral = Int(exactly: double) else { + return nil + } + location = integral + } + let _ = scanner.scanUpToCharacters(from: digitSet, into: nil) if scanner.isAtEnd { // return early if there are no integer characters after the first int in the string return nil } var length = 0 + savedLocation = scanner.scanLocation guard scanner.scanInt(&length) else { return nil } + if !scanner.isAtEnd { + if scanner.scanString(".", into: nil) { + scanner.scanLocation = savedLocation + var double = 0.0 + guard scanner.scanDouble(&double) else { + return nil + } + guard let integral = Int(exactly: double) else { + return nil + } + length = integral + } + } + + self.location = location self.length = length } diff --git a/stdlib/public/SDK/Foundation/PlistEncoder.swift b/stdlib/public/SDK/Foundation/PlistEncoder.swift index d7203fcfc9b..df898d27ffc 100644 --- a/stdlib/public/SDK/Foundation/PlistEncoder.swift +++ b/stdlib/public/SDK/Foundation/PlistEncoder.swift @@ -47,7 +47,7 @@ open class PropertyListEncoder { /// /// - parameter value: The value to encode. /// - returns: A new `Data` value containing the encoded property list data. - /// - throws: `EncodingError.invalidValue` if a non-comforming floating-point value is encountered during encoding, and the encoding strategy is `.throw`. + /// - throws: `EncodingError.invalidValue` if a non-conforming floating-point value is encountered during encoding, and the encoding strategy is `.throw`. /// - throws: An error if any value throws an error during encoding. open func encode(_ value: Value) throws -> Data { let encoder = _PlistEncoder(options: self.options) @@ -122,7 +122,7 @@ fileprivate class _PlistEncoder : Encoder { /// Returns whether a new element can be encoded at this coding path. /// /// `true` if an element has not yet been encoded at this coding path; `false` otherwise. - var canEncodeNewElement: Bool { + var canEncodeNewValue: Bool { // Every time a new value gets encoded, the key it's encoded for is pushed onto the coding path (even if it's a nil key from an unkeyed container). // At the same time, every time a container is requested, a new value gets pushed onto the storage stack. // If there are more values on the storage stack than on the coding path, it means the value is requesting more than one container, which violates the precondition. @@ -132,39 +132,43 @@ fileprivate class _PlistEncoder : Encoder { return self.storage.count == self.codingPath.count } - /// Asserts that a new container can be requested at this coding path. - /// `preconditionFailure()`s if one cannot be requested. - func assertCanRequestNewContainer() { - guard self.canEncodeNewElement else { - let previousContainerType: String - if self.storage.containers.last is NSDictionary { - previousContainerType = "keyed" - } else if self.storage.containers.last is NSArray { - previousContainerType = "unkeyed" - } else { - previousContainerType = "single value" - } - - preconditionFailure("Attempt to encode with new container when already encoded with \(previousContainerType) container.") - } - } - // MARK: - Encoder Methods func container(keyedBy: Key.Type) -> KeyedEncodingContainer { - assertCanRequestNewContainer() - let topContainer = self.storage.pushKeyedContainer() + // If an existing keyed container was already requested, return that one. + let topContainer: NSMutableDictionary + if self.canEncodeNewValue { + // We haven't yet pushed a container at this level; do so here. + topContainer = self.storage.pushKeyedContainer() + } else { + guard let container = self.storage.containers.last as? NSMutableDictionary else { + preconditionFailure("Attempt to push new keyed encoding container when already previously encoded at this path.") + } + + topContainer = container + } + let container = _PlistKeyedEncodingContainer(referencing: self, codingPath: self.codingPath, wrapping: topContainer) return KeyedEncodingContainer(container) } func unkeyedContainer() -> UnkeyedEncodingContainer { - assertCanRequestNewContainer() - let topContainer = self.storage.pushUnkeyedContainer() + // If an existing unkeyed container was already requested, return that one. + let topContainer: NSMutableArray + if self.canEncodeNewValue { + // We haven't yet pushed a container at this level; do so here. + topContainer = self.storage.pushUnkeyedContainer() + } else { + guard let container = self.storage.containers.last as? NSMutableArray else { + preconditionFailure("Attempt to push new unkeyed encoding container when already previously encoded at this path.") + } + + topContainer = container + } + return _PlistUnkeyedEncodingContainer(referencing: self, codingPath: self.codingPath, wrapping: topContainer) } func singleValueContainer() -> SingleValueEncodingContainer { - assertCanRequestNewContainer() return self } } @@ -382,106 +386,89 @@ fileprivate struct _PlistUnkeyedEncodingContainer : UnkeyedEncodingContainer { } extension _PlistEncoder : SingleValueEncodingContainer { - // MARK: - Utility Methods - - /// Asserts that a single value can be encoded at the current coding path (i.e. that one has not already been encoded through this container). - /// `preconditionFailure()`s if one cannot be encoded. - /// - /// This is similar to assertCanRequestNewContainer above. - func assertCanEncodeSingleValue() { - guard self.canEncodeNewElement else { - let previousContainerType: String - if self.storage.containers.last is NSDictionary { - previousContainerType = "keyed" - } else if self.storage.containers.last is NSArray { - previousContainerType = "unkeyed" - } else { - preconditionFailure("Attempt to encode multiple values in a single value container.") - } - - preconditionFailure("Attempt to encode with new container when already encoded with \(previousContainerType) container.") - } - } - // MARK: - SingleValueEncodingContainer Methods + func assertCanEncodeNewValue() { + precondition(self.canEncodeNewValue, "Attempt to encode value through single value container when previously value already encoded.") + } + func encodeNil() throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: _plistNullNSString) } func encode(_ value: Bool) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: Int) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: Int8) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: Int16) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: Int32) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: Int64) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: UInt) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: UInt8) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: UInt16) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: UInt32) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: UInt64) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: String) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: Float) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: Double) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() self.storage.push(container: box(value)) } func encode(_ value: T) throws { - assertCanEncodeSingleValue() + assertCanEncodeNewValue() try self.storage.push(container: box(value)) } } @@ -576,7 +563,7 @@ fileprivate class _PlistReferencingEncoder : _PlistEncoder { // MARK: - Coding Path Operations - override var canEncodeNewElement: Bool { + override var canEncodeNewValue: Bool { // With a regular encoder, the storage and coding path grow together. // A referencing encoder, however, inherits its parents coding path, as well as the key it was created for. // We have to take this into account. diff --git a/stdlib/public/SDK/GLKit/CMakeLists.txt b/stdlib/public/SDK/GLKit/CMakeLists.txt index fa8ab37583f..fec85f40a35 100644 --- a/stdlib/public/SDK/GLKit/CMakeLists.txt +++ b/stdlib/public/SDK/GLKit/CMakeLists.txt @@ -7,9 +7,10 @@ add_swift_library(swiftGLKit ${SWIFT_SDK_OVERLAY_LIBRARY_BUILD_TYPES} IS_SDK_OVE SWIFT_COMPILE_FLAGS "${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS}" LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}" TARGET_SDKS OSX IOS IOS_SIMULATOR TVOS TVOS_SIMULATOR - SWIFT_MODULE_DEPENDS_OSX Darwin AppKit CoreData CoreGraphics CoreImage Dispatch Foundation IOKit ObjectiveC QuartzCore simd XPC # auto-updated - SWIFT_MODULE_DEPENDS_IOS Darwin CoreGraphics CoreImage Dispatch Foundation ObjectiveC os QuartzCore simd UIKit # auto-updated - SWIFT_MODULE_DEPENDS_TVOS Darwin CoreGraphics CoreImage Dispatch Foundation ObjectiveC QuartzCore simd UIKit # auto-updated + SWIFT_MODULE_DEPENDS_OSX Darwin AppKit CoreData CoreFoundation CoreGraphics CoreImage Dispatch Foundation IOKit ModelIO ObjectiveC QuartzCore simd XPC # auto-updated + SWIFT_MODULE_DEPENDS_IOS Darwin CoreFoundation CoreGraphics CoreImage Dispatch Foundation ModelIO ObjectiveC QuartzCore simd UIKit # auto-updated + os + SWIFT_MODULE_DEPENDS_TVOS Darwin CoreFoundation CoreGraphics CoreImage Dispatch Foundation ModelIO ObjectiveC QuartzCore simd UIKit # auto-updated FRAMEWORK_DEPENDS GLKit DEPLOYMENT_VERSION_OSX ${SWIFTLIB_DEPLOYMENT_VERSION_GLKIT_OSX} diff --git a/stdlib/public/SDK/Intents/CMakeLists.txt b/stdlib/public/SDK/Intents/CMakeLists.txt index edd48332e1c..f65968baad1 100644 --- a/stdlib/public/SDK/Intents/CMakeLists.txt +++ b/stdlib/public/SDK/Intents/CMakeLists.txt @@ -8,6 +8,7 @@ add_swift_library(swiftIntents ${SWIFT_SDK_OVERLAY_LIBRARY_BUILD_TYPES} IS_SDK_O INGetCarLockStatusIntentResponse.swift INGetCarPowerLevelStatusIntentResponse.swift INIntegerResolutionResult.swift + INParameter.swift INRequestRideIntent.swift INSaveProfileInCarIntent.swift INSearchCallHistoryIntent.swift diff --git a/stdlib/public/SDK/Intents/INParameter.swift b/stdlib/public/SDK/Intents/INParameter.swift new file mode 100644 index 00000000000..cb5a3c921ac --- /dev/null +++ b/stdlib/public/SDK/Intents/INParameter.swift @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +@_exported import Intents +import Foundation + +#if os(iOS) || os(watchOS) +@available(iOS 11.0, watchOS 4.0, *) +extension INParameter { + @nonobjc + public convenience init?(keyPath: KeyPath) { + if let aClass = Root.self as? AnyClass, let keyPathString = keyPath._kvcKeyPathString { + self.init(for: aClass, keyPath: keyPathString) + } else { + return nil + } + } +} +#endif diff --git a/stdlib/public/SDK/Intents/INSearchCallHistoryIntent.swift b/stdlib/public/SDK/Intents/INSearchCallHistoryIntent.swift index 1e65ae32491..27000f1ceb3 100644 --- a/stdlib/public/SDK/Intents/INSearchCallHistoryIntent.swift +++ b/stdlib/public/SDK/Intents/INSearchCallHistoryIntent.swift @@ -14,27 +14,28 @@ import Foundation #if os(iOS) || os(watchOS) -@available(iOS 11.0, watchOS 4.0, *) +@available(iOS 10.0, watchOS 3.2, *) extension INSearchCallHistoryIntent { - @nonobjc - public convenience init( - dateCreated: INDateComponentsRange? = nil, - recipient: INPerson? = nil, - callCapabilities: INCallCapabilityOptions, - callTypes: INCallRecordTypeOptions, - unseen: Bool? = nil - ) { + @available(iOS 10.0, watchOS 3.2, *) + @nonobjc + public convenience init( + dateCreated: INDateComponentsRange? = nil, + recipient: INPerson? = nil, + callCapabilities: INCallCapabilityOptions, + callTypes: INCallRecordTypeOptions, + unseen: Bool? = nil + ) { + self.init(__dateCreated: dateCreated, + recipient: recipient, + callCapabilities: callCapabilities, + callTypes: callTypes, + unseen: unseen.map { NSNumber(value: $0) }) + } - self.init(__dateCreated: dateCreated, - recipient: recipient, - callCapabilities: callCapabilities, - callTypes: callTypes, - unseen: unseen.map { NSNumber(value: $0) }) - } - - @nonobjc - public final var unseen: Bool? { - return __unseen?.boolValue - } + @available(iOS 11.0, watchOS 4.0, *) + @nonobjc + public final var unseen: Bool? { + return __unseen?.boolValue + } } #endif diff --git a/stdlib/public/SDK/ModelIO/CMakeLists.txt b/stdlib/public/SDK/ModelIO/CMakeLists.txt new file mode 100644 index 00000000000..28d62fa8d68 --- /dev/null +++ b/stdlib/public/SDK/ModelIO/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.4.3) +include("../../../../cmake/modules/StandaloneOverlay.cmake") + +add_swift_library(swiftModelIO ${SWIFT_SDK_OVERLAY_LIBRARY_BUILD_TYPES} IS_SDK_OVERLAY + ModelIO.swift + + SWIFT_COMPILE_FLAGS "${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS}" + LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}" + TARGET_SDKS OSX IOS IOS_SIMULATOR TVOS TVOS_SIMULATOR + + SWIFT_MODULE_DEPENDS_OSX Darwin CoreFoundation CoreGraphics Dispatch Foundation IOKit ObjectiveC simd # auto-updated + SWIFT_MODULE_DEPENDS_IOS Darwin CoreFoundation CoreGraphics Dispatch Foundation ObjectiveC simd # auto-updated + SWIFT_MODULE_DEPENDS_TVOS Darwin CoreFoundation CoreGraphics Dispatch Foundation ObjectiveC simd # auto-updated + FRAMEWORK_DEPENDS ModelIO + + DEPLOYMENT_VERSION_OSX ${SWIFTLIB_DEPLOYMENT_VERSION_MODELIO_OSX} +) diff --git a/stdlib/public/SDK/ModelIO/ModelIO.swift b/stdlib/public/SDK/ModelIO/ModelIO.swift new file mode 100644 index 00000000000..8347ec6273b --- /dev/null +++ b/stdlib/public/SDK/ModelIO/ModelIO.swift @@ -0,0 +1,153 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +@_exported import ModelIO +import simd + +@available(OSX, introduced: 10.13) +@available(iOS, introduced: 11.0) +@available(tvOS, introduced: 11.0) +extension MDLSkinDeformer { + public func jointBindTransforms() -> [float4x4] { + let jointCount = jointPaths.count + var jointBindTransforms = [float4x4](repeating: float4x4(), count: jointCount) + copyJointBindTransforms(into: &jointBindTransforms[0], maxCount: jointCount) + return jointBindTransforms + } +} + +@available(OSX, introduced: 10.13) +@available(iOS, introduced: 11.0) +@available(tvOS, introduced: 11.0) +extension MDLAnimatedValue { + @nonobjc public func getTimes() -> [Double] { + var times = [Double](repeating: 0, count: Int(timeSampleCount)) + copyTimes(into: ×[0], maxCount: timeSampleCount) + return times + } +} + +@available(OSX, introduced: 10.13) +@available(iOS, introduced: 11.0) +@available(tvOS, introduced: 11.0) +extension MDLAnimatedMatrix4x4 { + public func getFloat4x4Array() -> [float4x4] { + var values = [float4x4](repeating: float4x4(), count: Int(timeSampleCount)) + copyFloat4x4Array(into: &values[0], maxCount: timeSampleCount) + return values + } + + public func getDouble4x4Array() -> [double4x4] { + var values = [double4x4](repeating: double4x4(), count: Int(timeSampleCount)) + copyDouble4x4Array(into: &values[0], maxCount: timeSampleCount) + return values + } +} + +@available(OSX, introduced: 10.13) +@available(iOS, introduced: 11.0) +@available(tvOS, introduced: 11.0) +extension MDLAnimatedScalarArray { + @nonobjc public func getFloatArray(atTime time: TimeInterval) -> [Float] { + var values = [Float](repeating: 0, count: Int(elementsCount)) + copyFloat(into: &values[0], maxCount: elementsCount, atTime: time) + return values + } + + @nonobjc public func getDoubleArray(atTime time: TimeInterval) -> [Double] { + var values = [Double](repeating: 0, count: Int(elementsCount)) + copyDouble(into: &values[0], maxCount: elementsCount, atTime: time) + return values + } + + @nonobjc public func getFloatArrays() -> [Float] { + let count = elementsCount * timeSampleCount + var values = [Float](repeating: 0, count: Int(count)) + copyFloat(into: &values[0], maxCount: count) + return values + } + + @nonobjc public func getDoubleArrays() -> [Double] { + let count = elementsCount * timeSampleCount + var values = [Double](repeating: 0, count: Int(count)) + copyDouble(into: &values[0], maxCount: count) + return values + } +} + +@available(OSX, introduced: 10.13) +@available(iOS, introduced: 11.0) +@available(tvOS, introduced: 11.0) +extension MDLAnimatedScalar { + @nonobjc public func getFloatArray() -> [Float] { + var values = [Float](repeating: 0, count: Int(timeSampleCount)) + copyFloatArray(into: &values[0], maxCount: timeSampleCount) + return values + } + + @nonobjc public func getDoubleArray() -> [Double] { + var values = [Double](repeating: 0, count: Int(timeSampleCount)) + copyDoubleArray(into: &values[0], maxCount: timeSampleCount) + return values + } +} + +@available(OSX, introduced: 10.13) +@available(iOS, introduced: 11.0) +@available(tvOS, introduced: 11.0) +extension MDLAnimatedVector2 { + public func getFloat2Array() -> [float2] { + var values = [float2](repeating: float2(), count: Int(timeSampleCount)) + copyFloat2Array(into: &values[0], maxCount: timeSampleCount) + return values + } + + public func getDouble2Array() -> [double2] { + var values = [double2](repeating: double2(), count: Int(timeSampleCount)) + copyDouble2Array(into: &values[0], maxCount: timeSampleCount) + return values + } +} + +@available(OSX, introduced: 10.13) +@available(iOS, introduced: 11.0) +@available(tvOS, introduced: 11.0) +extension MDLAnimatedVector3 { + public func getFloat3Array() -> [float3] { + var values = [float3](repeating: float3(), count: Int(timeSampleCount)) + copyFloat3Array(into: &values[0], maxCount: timeSampleCount) + return values + } + + public func getDouble3Array() -> [double3] { + var values = [double3](repeating: double3(), count: Int(timeSampleCount)) + copyDouble3Array(into: &values[0], maxCount: timeSampleCount) + return values + } +} + +@available(OSX, introduced: 10.13) +@available(iOS, introduced: 11.0) +@available(tvOS, introduced: 11.0) +extension MDLAnimatedVector4 { + public func getFloat4Array() -> [float4] { + var values = [float4](repeating: float4(), count: timeSampleCount) + copyFloat4Array(into: &values[0], maxCount: timeSampleCount) + return values + } + + public func getDouble4Array() -> [double4] { + var values = [double4](repeating: double4(), count: timeSampleCount) + copyDouble4Array(into: &values[0], maxCount: timeSampleCount) + return values + } +} diff --git a/stdlib/public/SDK/UIKit/UIKit.swift b/stdlib/public/SDK/UIKit/UIKit.swift index 29b2991af85..f37db95da49 100644 --- a/stdlib/public/SDK/UIKit/UIKit.swift +++ b/stdlib/public/SDK/UIKit/UIKit.swift @@ -13,6 +13,10 @@ import Foundation @_exported import UIKit +#if os(iOS) || os(tvOS) +import _SwiftUIKitOverlayShims +#endif + //===----------------------------------------------------------------------===// // UIGeometry //===----------------------------------------------------------------------===// @@ -277,13 +281,15 @@ extension UIContentSizeCategory { #if os(iOS) || os(tvOS) @available(iOS 11.0, tvOS 11.0, *) extension UIFocusEnvironment { + @available(iOS 11.0, tvOS 11.0, *) public func contains(_ environment: UIFocusEnvironment) -> Bool { - return UIFocusSystem.environment(self, contains: environment) + return _swift_UIKit_UIFocusEnvironmentContainsEnvironment(self, environment) } } @available(iOS 11.0, tvOS 11.0, *) extension UIFocusItem { + @available(iOS 11.0, tvOS 11.0, *) public var isFocused: Bool { return self === UIScreen.main.focusedItem } diff --git a/stdlib/public/SwiftShims/CMakeLists.txt b/stdlib/public/SwiftShims/CMakeLists.txt index ad8293ad998..782822b0288 100644 --- a/stdlib/public/SwiftShims/CMakeLists.txt +++ b/stdlib/public/SwiftShims/CMakeLists.txt @@ -16,9 +16,10 @@ set(sources Visibility.h DispatchOverlayShims.h - ObjectiveCOverlayShims.h OSOverlayShims.h + ObjectiveCOverlayShims.h SafariServicesOverlayShims.h + UIKitOverlayShims.h XCTestOverlayShims.h XPCOverlayShims.h diff --git a/stdlib/public/SwiftShims/KeyPath.h b/stdlib/public/SwiftShims/KeyPath.h index 7da463717c2..5f3b0218a83 100644 --- a/stdlib/public/SwiftShims/KeyPath.h +++ b/stdlib/public/SwiftShims/KeyPath.h @@ -55,9 +55,12 @@ static const __swift_uint32_t _SwiftKeyPathComponentHeader_OptionalTag = 3; static const __swift_uint32_t _SwiftKeyPathComponentHeader_MaximumOffsetPayload + = 0x1FFFFFFCU; + +static const __swift_uint32_t _SwiftKeyPathComponentHeader_UnresolvedIndirectOffsetPayload = 0x1FFFFFFDU; - -static const __swift_uint32_t _SwiftKeyPathComponentHeader_UnresolvedOffsetPayload + +static const __swift_uint32_t _SwiftKeyPathComponentHeader_UnresolvedFieldOffsetPayload = 0x1FFFFFFEU; static const __swift_uint32_t _SwiftKeyPathComponentHeader_OutOfLineOffsetPayload @@ -87,8 +90,6 @@ static const __swift_uint32_t _SwiftKeyPathComponentHeader_ComputedIDResolutionM = 0x0000000FU; static const __swift_uint32_t _SwiftKeyPathComponentHeader_ComputedIDResolved = 0x00000000U; -static const __swift_uint32_t _SwiftKeyPathComponentHeader_ComputedIDUnresolvedFieldOffset - = 0x00000001U; static const __swift_uint32_t _SwiftKeyPathComponentHeader_ComputedIDUnresolvedIndirectPointer = 0x00000002U; diff --git a/stdlib/public/SwiftShims/UIKitOverlayShims.h b/stdlib/public/SwiftShims/UIKitOverlayShims.h new file mode 100644 index 00000000000..c98552bb77b --- /dev/null +++ b/stdlib/public/SwiftShims/UIKitOverlayShims.h @@ -0,0 +1,34 @@ +//===--- UIKitOverlayShims.h ---===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===--------------------===// + +#ifndef SWIFT_STDLIB_SHIMS_UIKIT_OVERLAY_H +#define SWIFT_STDLIB_SHIMS_UIKIT_OVERLAY_H + +@import UIKit; + +#if __has_feature(nullability) +#pragma clang assume_nonnull begin +#endif + +#if TARGET_OS_TV || TARGET_OS_IOS +static inline BOOL _swift_UIKit_UIFocusEnvironmentContainsEnvironment(id environment, id otherEnvironment) { + return [UIFocusSystem environment:environment containsEnvironment:otherEnvironment]; +} +#endif // TARGET_OS_TV || TARGET_OS_IOS + +#if __has_feature(nullability) +#pragma clang assume_nonnull end +#endif + + +#endif // SWIFT_STDLIB_SHIMS_UIKIT_OVERLAY_H + diff --git a/stdlib/public/SwiftShims/module.modulemap b/stdlib/public/SwiftShims/module.modulemap index c33d512f81e..5b48587375f 100644 --- a/stdlib/public/SwiftShims/module.modulemap +++ b/stdlib/public/SwiftShims/module.modulemap @@ -40,6 +40,10 @@ module _SwiftSafariServicesOverlayShims { header "SafariServicesOverlayShims.h" } +module _SwiftUIKitOverlayShims { + header "UIKitOverlayShims.h" +} + module _SwiftXCTestOverlayShims { header "XCTestOverlayShims.h" } diff --git a/stdlib/public/core/CTypes.swift b/stdlib/public/core/CTypes.swift index 1f59945e662..923580a52dc 100644 --- a/stdlib/public/core/CTypes.swift +++ b/stdlib/public/core/CTypes.swift @@ -43,14 +43,14 @@ public typealias CShort = Int16 public typealias CInt = Int32 /// The C 'long' type. -#if os(Windows) && !CYGWIN && arch(x86_64) +#if os(Windows) && arch(x86_64) public typealias CLong = Int32 #else public typealias CLong = Int #endif /// The C 'long long' type. -#if os(Windows) && !CYGWIN && arch(x86_64) +#if os(Windows) && arch(x86_64) public typealias CLongLong = Int #else public typealias CLongLong = Int64 diff --git a/stdlib/public/core/Codable.swift b/stdlib/public/core/Codable.swift index 0403cef7e17..5dc5d49dda6 100644 --- a/stdlib/public/core/Codable.swift +++ b/stdlib/public/core/Codable.swift @@ -3233,15 +3233,33 @@ public extension RawRepresentable where RawValue == String, Self : Decodable { } //===----------------------------------------------------------------------===// -// Optional Conformance +// Optional/Collection Type Conformances //===----------------------------------------------------------------------===// +fileprivate func assertTypeIsEncodable(_ type: T.Type, in wrappingType: Any.Type) { + guard T.self is Encodable.Type else { + if T.self == Encodable.self || T.self == Codable.self { + preconditionFailure("\(wrappingType) does not conform to Encodable because Encodable does not conform to itself. You must use a concrete type to encode or decode.") + } else { + preconditionFailure("\(wrappingType) does not conform to Encodable because \(T.self) does not conform to Encodable.") + } + } +} + +fileprivate func assertTypeIsDecodable(_ type: T.Type, in wrappingType: Any.Type) { + guard T.self is Decodable.Type else { + if T.self == Decodable.self || T.self == Codable.self { + preconditionFailure("\(wrappingType) does not conform to Decodable because Decodable does not conform to itself. You must use a concrete type to encode or decode.") + } else { + preconditionFailure("\(wrappingType) does not conform to Decodable because \(T.self) does not conform to Decodable.") + } + } +} + // FIXME: Uncomment when conditional conformance is available. extension Optional : Encodable /* where Wrapped : Encodable */ { public func encode(to encoder: Encoder) throws { - guard Wrapped.self is Encodable.Type else { - preconditionFailure("\(type(of: self)) does not conform to Encodable because \(Wrapped.self) does not conform to Encodable.") - } + assertTypeIsEncodable(Wrapped.self, in: type(of: self)) var container = encoder.singleValueContainer() switch self { @@ -3253,12 +3271,9 @@ extension Optional : Encodable /* where Wrapped : Encodable */ { extension Optional : Decodable /* where Wrapped : Decodable */ { public init(from decoder: Decoder) throws { - // Initialize self here so we can print type(of: self). + // Initialize self here so we can get type(of: self). self = .none - - guard Wrapped.self is Decodable.Type else { - preconditionFailure("\(type(of: self)) does not conform to Decodable because \(Wrapped.self) does not conform to Decodable.") - } + assertTypeIsDecodable(Wrapped.self, in: type(of: self)) let container = try decoder.singleValueContainer() if !container.decodeNil() { @@ -3269,16 +3284,10 @@ extension Optional : Decodable /* where Wrapped : Decodable */ { } } -//===----------------------------------------------------------------------===// -// Collection Conformances -//===----------------------------------------------------------------------===// - // FIXME: Uncomment when conditional conformance is available. extension Array : Encodable /* where Element : Encodable */ { public func encode(to encoder: Encoder) throws { - guard Element.self is Encodable.Type else { - preconditionFailure("\(type(of: self)) does not conform to Encodable because \(Element.self) does not conform to Encodable.") - } + assertTypeIsEncodable(Element.self, in: type(of: self)) var container = encoder.unkeyedContainer() for element in self { @@ -3292,12 +3301,9 @@ extension Array : Encodable /* where Element : Encodable */ { extension Array : Decodable /* where Element : Decodable */ { public init(from decoder: Decoder) throws { - // Initialize self here so we can print type(of: self). + // Initialize self here so we can get type(of: self). self.init() - - guard Element.self is Decodable.Type else { - preconditionFailure("\(type(of: self)) does not conform to Decodable because \(Element.self) does not conform to Decodable.") - } + assertTypeIsDecodable(Element.self, in: type(of: self)) let metaType = (Element.self as! Decodable.Type) var container = try decoder.unkeyedContainer() @@ -3313,9 +3319,7 @@ extension Array : Decodable /* where Element : Decodable */ { extension Set : Encodable /* where Element : Encodable */ { public func encode(to encoder: Encoder) throws { - guard Element.self is Encodable.Type else { - preconditionFailure("\(type(of: self)) does not conform to Encodable because \(Element.self) does not conform to Encodable.") - } + assertTypeIsEncodable(Element.self, in: type(of: self)) var container = encoder.unkeyedContainer() for element in self { @@ -3329,12 +3333,9 @@ extension Set : Encodable /* where Element : Encodable */ { extension Set : Decodable /* where Element : Decodable */ { public init(from decoder: Decoder) throws { - // Initialize self here so we can print type(of: self). + // Initialize self here so we can get type(of: self). self.init() - - guard Element.self is Decodable.Type else { - preconditionFailure("\(type(of: self)) does not conform to Decodable because \(Element.self) does not conform to Decodable.") - } + assertTypeIsDecodable(Element.self, in: type(of: self)) let metaType = (Element.self as! Decodable.Type) var container = try decoder.unkeyedContainer() @@ -3366,13 +3367,8 @@ internal struct _DictionaryCodingKey : CodingKey { extension Dictionary : Encodable /* where Key : Encodable, Value : Encodable */ { public func encode(to encoder: Encoder) throws { - guard Key.self is Encodable.Type else { - preconditionFailure("\(type(of: self)) does not conform to Encodable because \(Key.self) does not conform to Encodable.") - } - - guard Value.self is Encodable.Type else { - preconditionFailure("\(type(of: self)) does not conform to Encodable because \(Value.self) does not conform to Encodable.") - } + assertTypeIsEncodable(Key.self, in: type(of: self)) + assertTypeIsEncodable(Value.self, in: type(of: self)) if Key.self == String.self { // Since the keys are already Strings, we can use them as keys directly. @@ -3411,14 +3407,8 @@ extension Dictionary : Decodable /* where Key : Decodable, Value : Decodable */ public init(from decoder: Decoder) throws { // Initialize self here so we can print type(of: self). self.init() - - guard Key.self is Decodable.Type else { - preconditionFailure("\(type(of: self)) does not conform to Decodable because \(Key.self) does not conform to Decodable.") - } - - guard Value.self is Decodable.Type else { - preconditionFailure("\(type(of: self)) does not conform to Decodable because \(Value.self) does not conform to Decodable.") - } + assertTypeIsDecodable(Key.self, in: type(of: self)) + assertTypeIsDecodable(Value.self, in: type(of: self)) if Key.self == String.self { // The keys are Strings, so we should be able to expect a keyed container. diff --git a/stdlib/public/core/DoubleWidth.swift.gyb b/stdlib/public/core/DoubleWidth.swift.gyb index 2fa5f8a48ca..70ae5d5d88e 100644 --- a/stdlib/public/core/DoubleWidth.swift.gyb +++ b/stdlib/public/core/DoubleWidth.swift.gyb @@ -176,9 +176,9 @@ public struct DoubleWidth : } // TODO: move to Int128 just like init(_builtinIntegerLiteral:) ? - return (n < _storage.low.countRepresentedWords) ? + return (n < _storage.low._countRepresentedWords) ? _storage.low._word(at: n) : - _storage.high._word(at: n - _storage.low.countRepresentedWords) + _storage.high._word(at: n - _storage.low._countRepresentedWords) } } diff --git a/stdlib/public/core/FloatingPoint.swift.gyb b/stdlib/public/core/FloatingPoint.swift.gyb index e34a1c1d56e..620c89727c6 100644 --- a/stdlib/public/core/FloatingPoint.swift.gyb +++ b/stdlib/public/core/FloatingPoint.swift.gyb @@ -1465,7 +1465,7 @@ public protocol BinaryFloatingPoint: FloatingPoint, ExpressibleByFloatLiteral { /// - Parameter value: A floating-point value. init(_ value: Double) -#if (!os(Windows) || CYGWIN) && (arch(i386) || arch(x86_64)) +#if !os(Windows) && (arch(i386) || arch(x86_64)) /// Creates a new instance from the given value, rounded to the closest /// possible representation. /// diff --git a/stdlib/public/core/FloatingPointParsing.swift.gyb b/stdlib/public/core/FloatingPointParsing.swift.gyb index 1fe02dd4f93..b64710810b2 100644 --- a/stdlib/public/core/FloatingPointParsing.swift.gyb +++ b/stdlib/public/core/FloatingPointParsing.swift.gyb @@ -38,7 +38,7 @@ internal func _isspace_clocale(_ u: UTF16.CodeUnit) -> Bool { % Self = floatName(bits) % if bits == 80: -#if (!os(Windows) || CYGWIN) && (arch(i386) || arch(x86_64)) +#if !os(Windows) && (arch(i386) || arch(x86_64)) % end //===--- Parsing ----------------------------------------------------------===// diff --git a/stdlib/public/core/FloatingPointTypes.swift.gyb b/stdlib/public/core/FloatingPointTypes.swift.gyb index d3fa0c6af87..5b4548b5505 100644 --- a/stdlib/public/core/FloatingPointTypes.swift.gyb +++ b/stdlib/public/core/FloatingPointTypes.swift.gyb @@ -64,7 +64,7 @@ else: }% % if bits == 80: -#if (!os(Windows) || CYGWIN) && (arch(i386) || arch(x86_64)) +#if !os(Windows) && (arch(i386) || arch(x86_64)) % end ${SelfDocComment} @@ -702,7 +702,7 @@ extension ${Self} : _ExpressibleByBuiltinIntegerLiteral, ExpressibleByIntegerLit } } -#if (!os(Windows) || CYGWIN) && (arch(i386) || arch(x86_64)) +#if !os(Windows) && (arch(i386) || arch(x86_64)) % builtinFloatLiteralBits = 80 extension ${Self} : _ExpressibleByBuiltinFloatLiteral { @@ -847,7 +847,7 @@ extension ${Self} { % That = src_type.stdlib_name % if srcBits == 80: -#if (!os(Windows) || CYGWIN) && (arch(i386) || arch(x86_64)) +#if !os(Windows) && (arch(i386) || arch(x86_64)) % end % if srcBits == bits: diff --git a/stdlib/public/core/HashedCollections.swift.gyb b/stdlib/public/core/HashedCollections.swift.gyb index f0811326b0a..ee3f173973f 100644 --- a/stdlib/public/core/HashedCollections.swift.gyb +++ b/stdlib/public/core/HashedCollections.swift.gyb @@ -1810,9 +1810,7 @@ public struct Dictionary : by keyForValue: (S.Element) throws -> Key ) rethrows where Value == [S.Element] { self = [:] - for value in values { - self[try keyForValue(value), default: []].append(value) - } + try _variantBuffer.nativeGroup(values, by: keyForValue) } internal init(_nativeBuffer: _NativeDictionaryBuffer) { @@ -5053,6 +5051,32 @@ internal enum _Variant${Self}Buffer<${TypeParametersDecl}> : _HashBuffer { #endif } } + + internal mutating func nativeGroup( + _ values: S, + by keyForValue: (S.Element) throws -> Key + ) rethrows where Value == [S.Element] { + defer { _fixLifetime(asNative) } + for value in values { + let key = try keyForValue(value) + var (i, found) = asNative._find(key, startBucket: asNative._bucket(key)) + if found { + asNative.values[i.offset].append(value) + } else { + let minCapacity = NativeBuffer.minimumCapacity( + minimumCount: asNative.count + 1, + maxLoadFactorInverse: _hashContainerDefaultMaxLoadFactorInverse) + + let (_, capacityChanged) = ensureUniqueNativeBuffer(minCapacity) + if capacityChanged { + i = asNative._find(key, startBucket: asNative._bucket(key)).pos + } + + asNative.initializeKey(key, value: [value], at: i.offset) + asNative.count += 1 + } + } + } %end /// - parameter idealBucket: The ideal bucket for the element being deleted. diff --git a/stdlib/public/core/HeapBuffer.swift b/stdlib/public/core/HeapBuffer.swift index 7c2e2944091..0ccb3019fe3 100644 --- a/stdlib/public/core/HeapBuffer.swift +++ b/stdlib/public/core/HeapBuffer.swift @@ -13,6 +13,7 @@ import SwiftShims typealias _HeapObject = SwiftShims.HeapObject +@_versioned internal protocol _HeapBufferHeader_ { associatedtype Value init(_ value: Value) diff --git a/stdlib/public/core/Integers.swift.gyb b/stdlib/public/core/Integers.swift.gyb index 77f35331244..692f4f86043 100644 --- a/stdlib/public/core/Integers.swift.gyb +++ b/stdlib/public/core/Integers.swift.gyb @@ -1548,7 +1548,7 @@ extension BinaryInteger { /// /// This property is a constant for instances of fixed-width integer types. @_transparent - public var countRepresentedWords: Int { + public var _countRepresentedWords: Int { return (self.bitWidth + ${word_bits} - 1) / ${word_bits} } @@ -1888,12 +1888,19 @@ extension BinaryInteger { #endif extension BinaryInteger { + // FIXME(integers): Should be removed once words get implemented properly. + // Meanhile it allows to conform to the BinaryInteger without implementing + // underscored APIs. https://bugs.swift.org/browse/SR-5275 + public func _word(at n: Int) -> UInt { + fatalError("Should be overridden") + } + // FIXME(integers): inefficient. Should get rid of _word(at:) and - // countRepresentedWords, and make `words` the basic operation. + // _countRepresentedWords, and make `words` the basic operation. public var words: [UInt] { var result = [UInt]() - result.reserveCapacity(countRepresentedWords) - for i in 0..= 0 { // masking is OK here because this we have already ensured // that Self.bitWidth > ${word_bits}. Not masking results in @@ -2794,7 +2801,7 @@ ${assignmentOperatorComment(x.operator, True)} @_transparent public func _word(at n: Int) -> UInt { _precondition(n >= 0, "Negative word index") - if _fastPath(n < countRepresentedWords) { + if _fastPath(n < _countRepresentedWords) { let shift = UInt(n._value) &* ${word_bits} let bitWidth = UInt(self.bitWidth._value) _sanityCheck(shift < bitWidth) diff --git a/stdlib/public/core/KeyPath.swift b/stdlib/public/core/KeyPath.swift index bec387d0bf6..9886d61ef6c 100644 --- a/stdlib/public/core/KeyPath.swift +++ b/stdlib/public/core/KeyPath.swift @@ -199,14 +199,19 @@ public class KeyPath: PartialKeyPath { func project(_ base: CurValue) -> Value? { func project2(_: NewValue.Type) -> Value? { - let newBase: NewValue = rawComponent.projectReadOnly(base) - if isLast { - _sanityCheck(NewValue.self == Value.self, - "key path does not terminate in correct type") - return unsafeBitCast(newBase, to: Value.self) - } else { - curBase = newBase - return nil + switch rawComponent.projectReadOnly(base, + to: NewValue.self, endingWith: Value.self) { + case .continue(let newBase): + if isLast { + _sanityCheck(NewValue.self == Value.self, + "key path does not terminate in correct type") + return unsafeBitCast(newBase, to: Value.self) + } else { + curBase = newBase + return nil + } + case .break(let result): + return result } } @@ -304,7 +309,9 @@ public class ReferenceWritableKeyPath: WritableKeyPath func project(_: NewValue.Type) -> Any { func project2(_ base: CurValue) -> Any { - return rawComponent.projectReadOnly(base) as NewValue + return rawComponent.projectReadOnly( + base, to: NewValue.self, endingWith: Value.self) + .assumingContinue } return _openExistential(base, do: project2) } @@ -350,58 +357,6 @@ public class ReferenceWritableKeyPath: WritableKeyPath // MARK: Implementation details -// Keypaths store word-sized values with 32-bit alignment for memory efficiency. -// Since RawPointer's APIs currently require alignment, this means we need -// to do some shuffling for the unaligned load/stores. - -extension UnsafeRawBufferPointer { - internal func _loadKeyPathWord(fromByteOffset offset: Int = 0, - as _: T.Type) -> T { - _sanityCheck(_isPOD(T.self) && - MemoryLayout.size == MemoryLayout.size, - "not a word-sized trivial type") - if MemoryLayout.size == 8 { - let words = load(fromByteOffset: offset, as: (Int32, Int32).self) - return unsafeBitCast(words, to: T.self) - } else if MemoryLayout.size == 4 { - return load(fromByteOffset: offset, as: T.self) - } else { - _sanityCheckFailure("unsupported architecture") - } - } -} - -extension UnsafeMutableRawBufferPointer { - internal func _loadKeyPathWord(fromByteOffset offset: Int = 0, - as _: T.Type) -> T { - _sanityCheck(_isPOD(T.self) && - MemoryLayout.size == MemoryLayout.size, - "not a word-sized trivial type") - if MemoryLayout.size == 8 { - let words = load(fromByteOffset: offset, as: (Int32, Int32).self) - return unsafeBitCast(words, to: T.self) - } else if MemoryLayout.size == 4 { - return load(fromByteOffset: offset, as: T.self) - } else { - _sanityCheckFailure("unsupported architecture") - } - } - internal func _storeKeyPathWord(of value: T, - toByteOffset offset: Int = 0) { - _sanityCheck(_isPOD(T.self) && - MemoryLayout.size == MemoryLayout.size, - "not a word-sized trivial type") - if MemoryLayout.size == 8 { - let words = unsafeBitCast(value, to: (Int32, Int32).self) - storeBytes(of: words, toByteOffset: offset, as: (Int32,Int32).self) - } else if MemoryLayout.size == 4 { - storeBytes(of: value, toByteOffset: offset, as: T.self) - } else { - _sanityCheckFailure("unsupported architecture") - } - } -} - internal enum KeyPathComponentKind { /// The keypath projects within the storage of the outer value, like a /// stored property in a struct. @@ -614,8 +569,11 @@ internal struct RawKeyPathComponent { static var outOfLineOffsetPayload: UInt32 { return _SwiftKeyPathComponentHeader_OutOfLineOffsetPayload } - static var unresolvedOffsetPayload: UInt32 { - return _SwiftKeyPathComponentHeader_UnresolvedOffsetPayload + static var unresolvedFieldOffsetPayload: UInt32 { + return _SwiftKeyPathComponentHeader_UnresolvedFieldOffsetPayload + } + static var unresolvedIndirectOffsetPayload: UInt32 { + return _SwiftKeyPathComponentHeader_UnresolvedIndirectOffsetPayload } static var computedMutatingFlag: UInt32 { return _SwiftKeyPathComponentHeader_ComputedMutatingFlag @@ -639,9 +597,6 @@ internal struct RawKeyPathComponent { static var computedIDResolved: UInt32 { return _SwiftKeyPathComponentHeader_ComputedIDResolved } - static var computedIDUnresolvedFieldOffset: UInt32 { - return _SwiftKeyPathComponentHeader_ComputedIDUnresolvedFieldOffset - } static var computedIDUnresolvedIndirectPointer: UInt32 { return _SwiftKeyPathComponentHeader_ComputedIDUnresolvedIndirectPointer } @@ -692,6 +647,12 @@ internal struct RawKeyPathComponent { _sanityCheckFailure("invalid header") } } + + // The component header is 4 bytes, but may be followed by an aligned + // pointer field for some kinds of component, forcing padding. + static var pointerAlignmentSkew: Int { + return MemoryLayout.size - MemoryLayout.size + } var bodySize: Int { switch kind { @@ -702,8 +663,8 @@ internal struct RawKeyPathComponent { return 0 case .computed: let ptrSize = MemoryLayout.size - // minimum two pointers for id and get - var total = ptrSize * 2 + // align to pointer, minimum two pointers for id and get + var total = Header.pointerAlignmentSkew + ptrSize * 2 // additional word for a setter if payload & Header.computedSettableFlag != 0 { total += ptrSize @@ -745,9 +706,8 @@ internal struct RawKeyPathComponent { var _computedIDValue: Int { _sanityCheck(header.kind == .computed, "not a computed property") - _sanityCheck(body.count >= MemoryLayout.size, - "component is not big enough") - return body._loadKeyPathWord(as: Int.self) + return body.load(fromByteOffset: Header.pointerAlignmentSkew, + as: Int.self) } var _computedID: ComputedPropertyID { @@ -761,11 +721,10 @@ internal struct RawKeyPathComponent { var _computedGetter: UnsafeRawPointer { _sanityCheck(header.kind == .computed, "not a computed property") - _sanityCheck(body.count >= MemoryLayout.size * 2, - "component is not big enough") - return body._loadKeyPathWord(fromByteOffset: MemoryLayout.size, - as: UnsafeRawPointer.self) + return body.load( + fromByteOffset: Header.pointerAlignmentSkew + MemoryLayout.size, + as: UnsafeRawPointer.self) } var _computedSetter: UnsafeRawPointer { @@ -773,11 +732,10 @@ internal struct RawKeyPathComponent { "not a computed property") _sanityCheck(header.payload & Header.computedSettableFlag != 0, "not a settable property") - _sanityCheck(body.count >= MemoryLayout.size * 3, - "component is not big enough") - return body._loadKeyPathWord(fromByteOffset: MemoryLayout.size * 2, - as: UnsafeRawPointer.self) + return body.load( + fromByteOffset: Header.pointerAlignmentSkew + MemoryLayout.size * 2, + as: UnsafeRawPointer.self) } var value: KeyPathComponent { @@ -835,7 +793,7 @@ internal struct RawKeyPathComponent { return } } - + func clone(into buffer: inout UnsafeMutableRawBufferPointer, endOfReferencePrefix: Bool) { var newHeader = header @@ -857,68 +815,108 @@ internal struct RawKeyPathComponent { .optionalWrap: break case .computed: + // Fields are pointer-aligned after the header + componentSize += Header.pointerAlignmentSkew // TODO: nontrivial arguments need to be copied by value witness _sanityCheck(header.payload & Header.computedHasArgumentsFlag == 0, "arguments not implemented") - buffer._storeKeyPathWord(of: _computedIDValue, toByteOffset: 4) - buffer._storeKeyPathWord(of: _computedGetter, - toByteOffset: 4 + MemoryLayout.size) + buffer.storeBytes(of: _computedIDValue, + toByteOffset: MemoryLayout.size, + as: Int.self) + buffer.storeBytes(of: _computedGetter, + toByteOffset: 2 * MemoryLayout.size, + as: UnsafeRawPointer.self) componentSize += MemoryLayout.size * 2 if header.payload & Header.computedSettableFlag != 0 { - buffer._storeKeyPathWord(of: _computedSetter, - toByteOffset: 4 + MemoryLayout.size * 2) + buffer.storeBytes(of: _computedSetter, + toByteOffset: MemoryLayout.size * 3, + as: UnsafeRawPointer.self) componentSize += MemoryLayout.size } } - _sanityCheck(buffer.count >= componentSize) buffer = UnsafeMutableRawBufferPointer( start: buffer.baseAddress.unsafelyUnwrapped + componentSize, - count: buffer.count - componentSize - ) + count: buffer.count - componentSize) } - - func projectReadOnly(_ base: CurValue) -> NewValue { + + enum ProjectionResult { + /// Continue projecting the key path with the given new value. + case `continue`(NewValue) + /// Stop projecting the key path and use the given value as the final + /// result of the projection. + case `break`(LeafValue) + + var assumingContinue: NewValue { + switch self { + case .continue(let x): + return x + case .break: + _sanityCheckFailure("should not have stopped key path projection") + } + } + } + + func projectReadOnly( + _ base: CurValue, + to: NewValue.Type, + endingWith: LeafValue.Type + ) -> ProjectionResult { switch value { case .struct(let offset): var base2 = base - return withUnsafeBytes(of: &base2) { + return .continue(withUnsafeBytes(of: &base2) { let p = $0.baseAddress.unsafelyUnwrapped.advanced(by: offset) // The contents of the struct should be well-typed, so we can assume // typed memory here. return p.assumingMemoryBound(to: NewValue.self).pointee - } - + }) + case .class(let offset): _sanityCheck(CurValue.self is AnyObject.Type, "base is not a class") let baseObj = unsafeBitCast(base, to: AnyObject.self) let basePtr = UnsafeRawPointer(Builtin.bridgeToRawPointer(baseObj)) defer { _fixLifetime(baseObj) } - return basePtr.advanced(by: offset) + return .continue(basePtr.advanced(by: offset) .assumingMemoryBound(to: NewValue.self) - .pointee - + .pointee) + case .get(id: _, get: let rawGet, argument: let argument), .mutatingGetSet(id: _, get: let rawGet, set: _, argument: let argument), .nonmutatingGetSet(id: _, get: let rawGet, set: _, argument: let argument): typealias Getter = @convention(thin) (CurValue, UnsafeRawPointer) -> NewValue let get = unsafeBitCast(rawGet, to: Getter.self) - return get(base, argument) + return .continue(get(base, argument)) case .optionalChain: - fatalError("TODO") - + _sanityCheck(CurValue.self == Optional.self, + "should be unwrapping optional value") + _sanityCheck(_isOptional(LeafValue.self), + "leaf result should be optional") + if let baseValue = unsafeBitCast(base, to: Optional.self) { + return .continue(baseValue) + } else { + // TODO: A more efficient way of getting the `none` representation + // of a dynamically-optional type... + return .break((Optional<()>.none as Any) as! LeafValue) + } + case .optionalForce: - fatalError("TODO") - + _sanityCheck(CurValue.self == Optional.self, + "should be unwrapping optional value") + return .continue(unsafeBitCast(base, to: Optional.self)!) + case .optionalWrap: - fatalError("TODO") + _sanityCheck(NewValue.self == Optional.self, + "should be wrapping optional value") + return .continue( + unsafeBitCast(base as Optional, to: NewValue.self)) } } - + func projectMutableAddress( _ base: UnsafeRawPointer, from _: CurValue.Type, @@ -989,7 +987,15 @@ internal struct RawKeyPathComponent { return UnsafeRawPointer(Builtin.addressof(&writeback.value)) case .optionalForce: - fatalError("TODO") + _sanityCheck(CurValue.self == Optional.self, + "should be unwrapping an optional value") + // Optional's layout happens to always put the payload at the start + // address of the Optional value itself, if a value is present at all. + let baseOptionalPointer + = base.assumingMemoryBound(to: Optional.self) + // Assert that a value exists + _ = baseOptionalPointer.pointee! + return base case .optionalChain, .optionalWrap, .get: _sanityCheckFailure("not a mutable key path component") @@ -1059,9 +1065,8 @@ internal struct KeyPathBuffer { init(base: UnsafeRawPointer) { let header = base.load(as: Header.self) data = UnsafeRawBufferPointer( - start: base + MemoryLayout
.size, - count: header.size - ) + start: base + MemoryLayout.size, + count: header.size) trivial = header.trivial hasReferencePrefix = header.hasReferencePrefix } @@ -1083,7 +1088,7 @@ internal struct KeyPathBuffer { let body: UnsafeRawBufferPointer let size = header.bodySize if size != 0 { - body = popRaw(size) + body = popRaw(size: size, alignment: 4) } else { body = UnsafeRawBufferPointer(start: nil, count: 0) } @@ -1094,22 +1099,15 @@ internal struct KeyPathBuffer { if data.count == 0 { nextType = nil } else { - if MemoryLayout.size == 8 { - // Words in the key path buffer are 32-bit aligned - nextType = unsafeBitCast(pop((Int32, Int32).self), - to: Any.Type.self) - } else if MemoryLayout.size == 4 { - nextType = pop(Any.Type.self) - } else { - _sanityCheckFailure("unexpected word size") - } + nextType = pop(Any.Type.self) } return (component, nextType) } mutating func pop(_ type: T.Type) -> T { _sanityCheck(_isPOD(T.self), "should be POD") - let raw = popRaw(MemoryLayout.size) + let raw = popRaw(size: MemoryLayout.size, + alignment: MemoryLayout.alignment) let resultBuf = UnsafeMutablePointer.allocate(capacity: 1) _memcpy(dest: resultBuf, src: UnsafeMutableRawPointer(mutating: raw.baseAddress.unsafelyUnwrapped), @@ -1118,13 +1116,18 @@ internal struct KeyPathBuffer { resultBuf.deallocate(capacity: 1) return result } - mutating func popRaw(_ size: Int) -> UnsafeRawBufferPointer { - _sanityCheck(data.count >= size, - "not enough space for next component?") - let result = UnsafeRawBufferPointer(start: data.baseAddress, count: size) + mutating func popRaw(size: Int, alignment: Int) -> UnsafeRawBufferPointer { + var baseAddress = data.baseAddress.unsafelyUnwrapped + var misalignment = Int(bitPattern: baseAddress) % alignment + if misalignment != 0 { + misalignment = alignment - misalignment + baseAddress += misalignment + } + + let result = UnsafeRawBufferPointer(start: baseAddress, count: size) data = UnsafeRawBufferPointer( - start: data.baseAddress.unsafelyUnwrapped + size, - count: data.count - size + start: baseAddress + size, + count: data.count - size - misalignment ) return result } @@ -1337,9 +1340,11 @@ public func _appendingKeyPaths< // Result buffer has room for both key paths' components, plus the // header, plus space for the middle type. - let resultSize = rootBuffer.data.count + leafBuffer.data.count - + MemoryLayout.size - + MemoryLayout.size + // Align up the root so that we can put the component type after it. + let alignMask = MemoryLayout.alignment - 1 + let rootSize = (rootBuffer.data.count + alignMask) & ~alignMask + let resultSize = rootSize + leafBuffer.data.count + + 2 * MemoryLayout.size // Tail-allocate space for the KVC string. let totalResultSize = (resultSize + appendedKVCLength + 3) & ~3 @@ -1357,40 +1362,40 @@ public func _appendingKeyPaths< count: resultSize) } - func pushRaw(_ count: Int) { - _sanityCheck(destBuffer.count >= count) - destBuffer = UnsafeMutableRawBufferPointer( - start: destBuffer.baseAddress.unsafelyUnwrapped + count, - count: destBuffer.count - count - ) - } - func pushType(_ type: Any.Type) { - let intSize = MemoryLayout.size - _sanityCheck(destBuffer.count >= intSize) - if intSize == 8 { - let words = unsafeBitCast(type, to: (UInt32, UInt32).self) - destBuffer.storeBytes(of: words.0, - as: UInt32.self) - destBuffer.storeBytes(of: words.1, toByteOffset: 4, - as: UInt32.self) - } else if intSize == 4 { - destBuffer.storeBytes(of: type, as: Any.Type.self) - } else { - _sanityCheckFailure("unsupported architecture") + func pushRaw(size: Int, alignment: Int) + -> UnsafeMutableRawBufferPointer { + var baseAddress = destBuffer.baseAddress.unsafelyUnwrapped + var misalign = Int(bitPattern: baseAddress) % alignment + if misalign != 0 { + misalign = alignment - misalign + baseAddress = baseAddress.advanced(by: misalign) } - pushRaw(intSize) + let result = UnsafeMutableRawBufferPointer( + start: baseAddress, + count: size) + destBuffer = UnsafeMutableRawBufferPointer( + start: baseAddress + size, + count: destBuffer.count - size - misalign) + return result + } + func push(_ value: T) { + let buf = pushRaw(size: MemoryLayout.size, + alignment: MemoryLayout.alignment) + buf.storeBytes(of: value, as: T.self) } // Save space for the header. let leafIsReferenceWritable = type(of: leaf).kind == .reference let header = KeyPathBuffer.Header( - size: resultSize - MemoryLayout.size, + size: resultSize - MemoryLayout.size, trivial: rootBuffer.trivial && leafBuffer.trivial, hasReferencePrefix: rootBuffer.hasReferencePrefix || leafIsReferenceWritable ) - destBuffer.storeBytes(of: header, as: KeyPathBuffer.Header.self) - pushRaw(MemoryLayout.size) + push(header) + // Start the components at pointer alignment + _ = pushRaw(size: RawKeyPathComponent.Header.pointerAlignmentSkew, + alignment: 4) let leafHasReferencePrefix = leafBuffer.hasReferencePrefix @@ -1412,13 +1417,12 @@ public func _appendingKeyPaths< component.clone( into: &destBuffer, - endOfReferencePrefix: endOfReferencePrefix - ) + endOfReferencePrefix: endOfReferencePrefix) if let type = type { - pushType(type) + push(type) } else { // Insert our endpoint type between the root and leaf components. - pushType(Value.self) + push(Value.self as Any.Type) break } } @@ -1429,11 +1433,10 @@ public func _appendingKeyPaths< component.clone( into: &destBuffer, - endOfReferencePrefix: component.header.endOfReferencePrefix - ) + endOfReferencePrefix: component.header.endOfReferencePrefix) if let type = type { - pushType(type) + push(type) } else { break } @@ -1567,7 +1570,7 @@ internal func _getKeyPath_instantiateInline( let bufferPtr = objectPtr.advanced(by: keyPathObjectHeaderSize) let buffer = KeyPathBuffer(base: bufferPtr) - let totalSize = buffer.data.count + MemoryLayout.size + let totalSize = buffer.data.count + MemoryLayout.size let bufferData = UnsafeMutableRawBufferPointer( start: bufferPtr, count: totalSize) @@ -1607,16 +1610,19 @@ internal func _getKeyPathClassAndInstanceSize( let bufferPtr = pattern.advanced(by: keyPathObjectHeaderSize) var buffer = KeyPathBuffer(base: bufferPtr) - let size = buffer.data.count + MemoryLayout.size + let size = buffer.data.count + MemoryLayout.size scanComponents: while true { let header = buffer.pop(RawKeyPathComponent.Header.self) func popOffset() { - if header.payload == RawKeyPathComponent.Header.unresolvedOffsetPayload + if header.payload == RawKeyPathComponent.Header.unresolvedFieldOffsetPayload || header.payload == RawKeyPathComponent.Header.outOfLineOffsetPayload { _ = buffer.pop(UInt32.self) } + if header.payload == RawKeyPathComponent.Header.unresolvedIndirectOffsetPayload { + _ = buffer.pop(Int.self) + } } switch header.kind { @@ -1655,7 +1661,8 @@ internal func _getKeyPathClassAndInstanceSize( header.payload & RawKeyPathComponent.Header.computedHasArgumentsFlag == 0, "arguments not implemented yet") - _ = buffer.popRaw(MemoryLayout.size * (settable ? 3 : 2)) + _ = buffer.popRaw(size: MemoryLayout.size * (settable ? 3 : 2), + alignment: MemoryLayout.alignment) case .optionalChain, .optionalWrap: @@ -1672,7 +1679,8 @@ internal func _getKeyPathClassAndInstanceSize( if buffer.data.count == 0 { break } // Pop the type accessor reference. - _ = buffer.popRaw(MemoryLayout.size) + _ = buffer.popRaw(size: MemoryLayout.size, + alignment: MemoryLayout.alignment) } // Grab the class object for the key path type we'll end up with. @@ -1706,21 +1714,26 @@ internal func _instantiateKeyPathBuffer( var patternBuffer = origPatternBuffer let destHeaderPtr = origDestData.baseAddress.unsafelyUnwrapped - _sanityCheck(origDestData.count >= MemoryLayout.size) var destData = UnsafeMutableRawBufferPointer( - start: destHeaderPtr.advanced(by: MemoryLayout.size), - count: origDestData.count - MemoryLayout.size) + start: destHeaderPtr.advanced(by: MemoryLayout.size), + count: origDestData.count - MemoryLayout.size) func pushDest(_ value: T) { _sanityCheck(_isPOD(T.self)) var value2 = value let size = MemoryLayout.size - _sanityCheck(destData.count >= size) - _memcpy(dest: destData.baseAddress.unsafelyUnwrapped, src: &value2, + let alignment = MemoryLayout.alignment + var baseAddress = destData.baseAddress.unsafelyUnwrapped + var misalign = Int(bitPattern: baseAddress) % alignment + if misalign != 0 { + misalign = alignment - misalign + baseAddress = baseAddress.advanced(by: misalign) + } + _memcpy(dest: baseAddress, src: &value2, size: UInt(size)) destData = UnsafeMutableRawBufferPointer( - start: destData.baseAddress.unsafelyUnwrapped.advanced(by: size), - count: destData.count - size) + start: baseAddress.advanced(by: size), + count: destData.count - size - misalign) } // Track where the reference prefix begins. @@ -1729,12 +1742,16 @@ internal func _instantiateKeyPathBuffer( // Instantiate components that need it. var base: Any.Type = rootType + // Some pattern forms are pessimistically larger than what we need in the + // instantiated key path. Keep track of this. + var shrinkage = 0 while true { let componentAddr = destData.baseAddress.unsafelyUnwrapped let header = patternBuffer.pop(RawKeyPathComponent.Header.self) + func tryToResolveOffset() { - if header.payload == RawKeyPathComponent.Header.unresolvedOffsetPayload { + if header.payload == RawKeyPathComponent.Header.unresolvedFieldOffsetPayload { // Look up offset in type metadata. The value in the pattern is the // offset within the metadata object. let metadataPtr = unsafeBitCast(base, to: UnsafeRawPointer.self) @@ -1749,6 +1766,25 @@ internal func _instantiateKeyPathBuffer( return } + if header.payload == RawKeyPathComponent.Header.unresolvedIndirectOffsetPayload { + // Look up offset in the indirectly-referenced variable we have a + // pointer. + let offsetVar = patternBuffer.pop(UnsafeRawPointer.self) + let offsetValue = UInt32(offsetVar.load(as: UInt.self)) + // Rewrite the header for a resolved offset. + var newHeader = header + newHeader.payload = RawKeyPathComponent.Header.outOfLineOffsetPayload + pushDest(newHeader) + pushDest(offsetValue) + // On 64-bit systems the pointer to the ivar offset variable is + // pointer-sized and -aligned, but the resulting offset ought to be + // 32 bits only, so we can shrink the result object a bit. + if MemoryLayout.size == 8 { + shrinkage += MemoryLayout.size + } + return + } + // Otherwise, just transfer the pre-resolved component. pushDest(header) if header.payload == RawKeyPathComponent.Header.outOfLineOffsetPayload { @@ -1790,15 +1826,6 @@ internal func _instantiateKeyPathBuffer( case RawKeyPathComponent.Header.computedIDResolved: // Nothing to do. break - case RawKeyPathComponent.Header.computedIDUnresolvedFieldOffset: - // The value in the pattern is an offset into the type metadata that - // points to the field offset for the stored property identifying the - // component. - _sanityCheck(header.payload - & RawKeyPathComponent.Header.computedIDByStoredPropertyFlag != 0, - "only stored property IDs should need offset resolution") - let metadataPtr = unsafeBitCast(base, to: UnsafeRawPointer.self) - id = metadataPtr.load(fromByteOffset: id, as: Int.self) case RawKeyPathComponent.Header.computedIDUnresolvedIndirectPointer: // The value in the pattern is a pointer to the actual unique word-sized // value in memory. @@ -1827,29 +1854,18 @@ internal func _instantiateKeyPathBuffer( if patternBuffer.data.count == 0 { break } // Resolve the component type. - if MemoryLayout.size == 4 { - let componentTyAccessor = patternBuffer.pop(MetadataAccessor.self) - base = unsafeBitCast(componentTyAccessor(arguments), to: Any.Type.self) - pushDest(base) - } else if MemoryLayout.size == 8 { - let componentTyAccessorWords = patternBuffer.pop((UInt32,UInt32).self) - let componentTyAccessor = unsafeBitCast(componentTyAccessorWords, - to: MetadataAccessor.self) - base = unsafeBitCast(componentTyAccessor(arguments), to: Any.Type.self) - let componentTyWords = unsafeBitCast(base, - to: (UInt32, UInt32).self) - pushDest(componentTyWords) - } else { - fatalError("unsupported architecture") - } + let componentTyAccessor = patternBuffer.pop(MetadataAccessor.self) + base = unsafeBitCast(componentTyAccessor(arguments), to: Any.Type.self) + pushDest(base) previousComponentAddr = componentAddr } // We should have traversed both buffers. - _sanityCheck(patternBuffer.data.isEmpty && destData.isEmpty) + _sanityCheck(patternBuffer.data.isEmpty && destData.count == shrinkage) // Write out the header. - let destHeader = KeyPathBuffer.Header(size: origPatternBuffer.data.count, + let destHeader = KeyPathBuffer.Header( + size: origPatternBuffer.data.count - shrinkage, trivial: true, // TODO: nontrivial indexes hasReferencePrefix: endOfReferencePrefixComponent != nil) diff --git a/stdlib/public/core/Policy.swift b/stdlib/public/core/Policy.swift index 306d3fcde0f..8172198e163 100644 --- a/stdlib/public/core/Policy.swift +++ b/stdlib/public/core/Policy.swift @@ -104,7 +104,7 @@ public typealias StringLiteralType = String // IEEE Binary64, and we need 1 bit to represent the sign. Instead of using // 1025, we use the next round number -- 2048. public typealias _MaxBuiltinIntegerType = Builtin.Int2048 -#if (!os(Windows) || CYGWIN) && (arch(i386) || arch(x86_64)) +#if !os(Windows) && (arch(i386) || arch(x86_64)) public typealias _MaxBuiltinFloatType = Builtin.FPIEEE80 #else public typealias _MaxBuiltinFloatType = Builtin.FPIEEE64 diff --git a/stdlib/public/core/Runtime.swift.gyb b/stdlib/public/core/Runtime.swift.gyb index 4a097fd74fe..c1abf231660 100644 --- a/stdlib/public/core/Runtime.swift.gyb +++ b/stdlib/public/core/Runtime.swift.gyb @@ -340,7 +340,7 @@ internal struct _Buffer72 { % for bits in [ 32, 64, 80 ]: % if bits == 80: -#if (!os(Windows) || CYGWIN) && (arch(i386) || arch(x86_64)) +#if !os(Windows) && (arch(i386) || arch(x86_64)) % end @_silgen_name("swift_float${bits}ToString") diff --git a/stdlib/public/core/Sequence.swift b/stdlib/public/core/Sequence.swift index 2191fc21199..a47e3730525 100644 --- a/stdlib/public/core/Sequence.swift +++ b/stdlib/public/core/Sequence.swift @@ -323,9 +323,11 @@ public protocol IteratorProtocol { /// traverse a sequence should be considered O(*n*) unless documented /// otherwise. public protocol Sequence { + /// A type representing the sequence's elements. + associatedtype Element + /// A type that provides the sequence's iteration interface and /// encapsulates its iteration state. - associatedtype Element associatedtype Iterator : IteratorProtocol where Iterator.Element == Element /// A type that represents a subsequence of some of the sequence's elements. diff --git a/stdlib/public/core/StringCharacterView.swift b/stdlib/public/core/StringCharacterView.swift index 104b4e84c75..debf0ba1d8d 100644 --- a/stdlib/public/core/StringCharacterView.swift +++ b/stdlib/public/core/StringCharacterView.swift @@ -315,7 +315,6 @@ extension String.CharacterView : BidirectionalCollection { // others: // 0x3400-0xA4CF case 0x3400...0xa4cf: return true - // TODO: CJK punctuation // Repeat sub-300 check, this is beneficial for common cases of Latin // characters embedded within non-Latin script (e.g. newlines, spaces, @@ -324,8 +323,6 @@ extension String.CharacterView : BidirectionalCollection { // NOTE: CR-LF special case has already been checked. case 0x0000...0x02ff: return true - // TODO: general punctuation - // Non-combining kana: // 0x3041-0x3096 // 0x30A1-0x30FA @@ -344,6 +341,14 @@ extension String.CharacterView : BidirectionalCollection { // 0xAC00–0xD7AF case 0xac00...0xd7af: return true + // Common general use punctuation, excluding extenders: + // 0x2010-0x2029 + case 0x2010...0x2029: return true + + // CJK punctuation characters, excluding extenders: + // 0x3000-0x3029 + case 0x3000...0x3029: return true + default: return false } } diff --git a/stdlib/public/core/StringRangeReplaceableCollection.swift.gyb b/stdlib/public/core/StringRangeReplaceableCollection.swift.gyb index 8d8c3822b86..0028126d6c9 100644 --- a/stdlib/public/core/StringRangeReplaceableCollection.swift.gyb +++ b/stdlib/public/core/StringRangeReplaceableCollection.swift.gyb @@ -393,7 +393,7 @@ extension String { // [0, 1].flatMap { x in // if String(x) == "foo" { return "bar" } else { return nil } // } -// Note that the second overload is delcared on a more specific protocol. +// Note that the second overload is declared on a more specific protocol. // See: test/stdlib/StringFlatMap.swift for tests. extension Sequence { @available(swift, obsoleted: 4) diff --git a/stdlib/public/runtime/Errors.cpp b/stdlib/public/runtime/Errors.cpp index c50035632ac..225d16cf4cf 100644 --- a/stdlib/public/runtime/Errors.cpp +++ b/stdlib/public/runtime/Errors.cpp @@ -243,11 +243,29 @@ reportNow(uint32_t flags, const char *message) #endif } +LLVM_ATTRIBUTE_NOINLINE SWIFT_RUNTIME_EXPORT +void _swift_runtime_on_report(uintptr_t flags, const char *message, + RuntimeErrorDetails *details) { + // Do nothing. This function is meant to be used by the debugger. + + // The following is necessary to avoid calls from being optimized out. + asm volatile("" // Do nothing. + : // Output list, empty. + : "r" (flags), "r" (message), "r" (details) // Input list. + : // Clobber list, empty. + ); +} + +void swift::reportToDebugger(uintptr_t flags, const char *message, + RuntimeErrorDetails *details) { + _swift_runtime_on_report(flags, message, details); +} + /// Report a fatal error to system console, stderr, and crash logs. /// Does not crash by itself. void swift::swift_reportError(uint32_t flags, const char *message) { -#if NDEBUG +#if defined(__APPLE__) && NDEBUG flags &= ~FatalErrorFlags::ReportBacktrace; #endif reportNow(flags, message); diff --git a/stdlib/public/runtime/Exclusivity.cpp b/stdlib/public/runtime/Exclusivity.cpp index 999543e2ea9..f144698556e 100644 --- a/stdlib/public/runtime/Exclusivity.cpp +++ b/stdlib/public/runtime/Exclusivity.cpp @@ -64,23 +64,6 @@ static const char *getAccessName(ExclusivityFlags flags) { } } -LLVM_ATTRIBUTE_ALWAYS_INLINE -static void printConflictDetails(const char *oldAccessName, void *oldPC, - const char *newAccessName, void *newPC) { - fprintf(stderr, "Previous access (a %s) started at ", oldAccessName); - if (oldPC) { - dumpStackTraceEntry(0, oldPC, /*shortOutput=*/true); - fprintf(stderr, " (0x%lx).\n", (uintptr_t)oldPC); - } else { - fprintf(stderr, ".\n"); - } - - fprintf(stderr, "Current access (a %s) started at:\n", newAccessName); - // The top frame is in swift_beginAccess, don't print it. - constexpr unsigned framesToSkip = 2; - printCurrentBacktrace(framesToSkip); -} - LLVM_ATTRIBUTE_ALWAYS_INLINE static void reportExclusivityConflict(ExclusivityFlags oldAction, void *oldPC, ExclusivityFlags newFlags, void *newPC, @@ -94,14 +77,56 @@ static void reportExclusivityConflict(ExclusivityFlags oldAction, void *oldPC, return; } - fprintf(stderr, - "Simultaneous accesses to 0x%lx, but modification requires exclusive " - "access.\n", - (uintptr_t)pointer); - printConflictDetails(getAccessName(oldAction), oldPC, - getAccessName(getAccessAction(newFlags)), newPC); + constexpr unsigned maxMessageLength = 100; + constexpr unsigned maxAccessDescriptionLength = 50; + char message[maxMessageLength]; + snprintf(message, sizeof(message), + "Simultaneous accesses to 0x%lx, but modification requires " + "exclusive access", + (uintptr_t)pointer); + fprintf(stderr, "%s.\n", message); - if (isWarningOnly(newFlags)) { + char oldAccess[maxAccessDescriptionLength]; + snprintf(oldAccess, sizeof(oldAccess), + "Previous access (a %s) started at", getAccessName(oldAction)); + fprintf(stderr, "%s ", oldAccess); + if (oldPC) { + dumpStackTraceEntry(0, oldPC, /*shortOutput=*/true); + fprintf(stderr, " (0x%lx).\n", (uintptr_t)oldPC); + } else { + fprintf(stderr, ".\n"); + } + + char newAccess[maxAccessDescriptionLength]; + snprintf(newAccess, sizeof(newAccess), "Current access (a %s) started at", + getAccessName(getAccessAction(newFlags))); + fprintf(stderr, "%s:\n", newAccess); + // The top frame is in swift_beginAccess, don't print it. + constexpr unsigned framesToSkip = 1; + printCurrentBacktrace(framesToSkip); + + bool keepGoing = isWarningOnly(newFlags); + + RuntimeErrorDetails::Thread secondaryThread = { + .description = oldAccess, + .numFrames = 1, + .frames = &oldPC + }; + RuntimeErrorDetails details = { + .version = RuntimeErrorDetails::currentVersion, + .errorType = "exclusivity-violation", + .currentStackDescription = newAccess, + .framesToSkip = framesToSkip, + .memoryAddress = pointer, + .numExtraThreads = 1, + .threads = &secondaryThread + }; + uintptr_t flags = RuntimeErrorFlagNone; + if (!keepGoing) + flags = RuntimeErrorFlagFatal; + reportToDebugger(flags, message, &details); + + if (keepGoing) { return; } @@ -128,7 +153,7 @@ struct Access { void setNext(Access *next) { NextAndAction = - reinterpret_cast(next) | (NextAndAction & NextMask); + reinterpret_cast(next) | (NextAndAction & ActionMask); } ExclusivityFlags getAccessAction() const { @@ -187,8 +212,11 @@ public: return; } - for (Access *last = cur; cur != nullptr; last = cur, cur = cur->getNext()) { - if (last == access) { + Access *last = cur; + for (cur = cur->getNext(); cur != nullptr; + last = cur, cur = cur->getNext()) { + assert(last->getNext() == cur); + if (cur == access) { last->setNext(cur->getNext()); return; } diff --git a/stdlib/public/runtime/HeapObject.cpp b/stdlib/public/runtime/HeapObject.cpp index c9a311ca62b..992956e7c96 100644 --- a/stdlib/public/runtime/HeapObject.cpp +++ b/stdlib/public/runtime/HeapObject.cpp @@ -31,6 +31,7 @@ #include #include #include +#include "../SwiftShims/GlobalObjects.h" #include "../SwiftShims/RuntimeShims.h" #if SWIFT_OBJC_INTEROP # include @@ -227,6 +228,30 @@ OpaqueValue *swift::swift_projectBox(HeapObject *o) { return metadata->project(o); } +namespace { // Begin anonymous namespace. + +struct _SwiftEmptyBoxStorage { + HeapObject header; +}; + +swift::HeapLocalVariableMetadata _emptyBoxStorageMetadata; + +/// The singleton empty box storage object. +_SwiftEmptyBoxStorage _EmptyBoxStorage = { + // HeapObject header; + { + &_emptyBoxStorageMetadata, + } +}; + +} // End anonymous namespace. + +HeapObject *swift::swift_allocEmptyBox() { + auto heapObject = reinterpret_cast(&_EmptyBoxStorage); + SWIFT_RT_ENTRY_CALL(swift_retain)(heapObject); + return heapObject; +} + // Forward-declare this, but define it after swift_release. extern "C" LLVM_LIBRARY_VISIBILITY LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED void _swift_release_dealloc(HeapObject *object) SWIFT_CC(RegisterPreservingCC_IMPL); diff --git a/stdlib/public/runtime/SwiftObject.mm b/stdlib/public/runtime/SwiftObject.mm index 69f3c054d1f..16403224712 100644 --- a/stdlib/public/runtime/SwiftObject.mm +++ b/stdlib/public/runtime/SwiftObject.mm @@ -1425,17 +1425,48 @@ void swift_objc_swift3ImplicitObjCEntrypoint(id self, SEL selector, if (filenameLength > INT_MAX) filenameLength = INT_MAX; - - reporter( - flags, - "*** %*s:%zu:%zu: implicit Objective-C entrypoint %c[%s %s] " - "is deprecated and will be removed in Swift 4; " - "add explicit '@objc' to the declaration to emit the Objective-C " - "entrypoint in Swift 4 and suppress this message\n", - (int)filenameLength, filename, line, column, - isInstanceMethod ? '-' : '+', - class_getName([self class]), - sel_getName(selector)); + + char *message, *nullTerminatedFilename; + asprintf(&message, + "implicit Objective-C entrypoint %c[%s %s] is deprecated and will " + "be removed in Swift 4", + isInstanceMethod ? '-' : '+', + class_getName([self class]), + sel_getName(selector)); + asprintf(&nullTerminatedFilename, "%*s", (int)filenameLength, filename); + + RuntimeErrorDetails::FixIt fixit = { + .filename = nullTerminatedFilename, + .startLine = line, + .endLine = line, + .startColumn = column, + .endColumn = column, + .replacementText = "@objc " + }; + RuntimeErrorDetails::Note note = { + .description = "add '@objc' to expose this Swift declaration to Objective-C", + .numFixIts = 1, + .fixIts = &fixit + }; + RuntimeErrorDetails details = { + .version = RuntimeErrorDetails::currentVersion, + .errorType = "implicit-objc-entrypoint", + .framesToSkip = 1, + .numNotes = 1, + .notes = ¬e + }; + uintptr_t runtime_error_flags = RuntimeErrorFlagNone; + if (reporter == swift::fatalError) + runtime_error_flags = RuntimeErrorFlagFatal; + reportToDebugger(runtime_error_flags, message, &details); + + reporter(flags, + "*** %s:%zu:%zu: %s; add explicit '@objc' to the declaration to " + "emit the Objective-C entrypoint in Swift 4 and suppress this " + "message\n", + nullTerminatedFilename, line, column, message); + free(message); + free(nullTerminatedFilename); } #endif diff --git a/test/ClangImporter/Inputs/custom-modules/AvailabilityExtras.h b/test/ClangImporter/Inputs/custom-modules/AvailabilityExtras.h index 9c0c8c94d3e..c0befe5a2ad 100644 --- a/test/ClangImporter/Inputs/custom-modules/AvailabilityExtras.h +++ b/test/ClangImporter/Inputs/custom-modules/AvailabilityExtras.h @@ -1,3 +1,5 @@ +@import Foundation; + void unavail1(void) __attribute__((unavailable("first"))); void unavail1(void); void unavail1(void); @@ -84,3 +86,10 @@ struct NSSwiftUnavailableStruct { } __attribute__((availability(swift, unavailable))); void unavailableWithOS() __attribute__((availability(ios, deprecated=8.0))) __attribute__((availability(swift, unavailable))) __attribute__((availability(macosx, deprecated=10.10))) ; + +typedef NS_ENUM(NSInteger, NSEnumAddedCasesIn2017) { + NSEnumAddedCasesIn2017ExistingCaseOne, + NSEnumAddedCasesIn2017ExistingCaseTwo, + NSEnumAddedCasesIn2017ExistingCaseThree, + NSEnumAddedCasesIn2017NewCaseOne __attribute__((availability(macosx,introduced=10.13))) __attribute__((availability(ios,introduced=11.0))) __attribute__((availability(tvos,introduced=11.0))) __attribute__((availability(watchos,introduced=4.0))) +}; diff --git a/test/ClangImporter/Inputs/custom-modules/ObjCBridgeNonconforming.h b/test/ClangImporter/Inputs/custom-modules/ObjCBridgeNonconforming.h new file mode 100644 index 00000000000..e68e7b17088 --- /dev/null +++ b/test/ClangImporter/Inputs/custom-modules/ObjCBridgeNonconforming.h @@ -0,0 +1,6 @@ +@import ObjectiveC; +@import Foundation; + +@interface ObjCBridgeNonconforming +@property NSSet *> * _Nonnull foo; +@end diff --git a/test/ClangImporter/Inputs/custom-modules/module.map b/test/ClangImporter/Inputs/custom-modules/module.map index ab94105d215..60cb1fe6331 100644 --- a/test/ClangImporter/Inputs/custom-modules/module.map +++ b/test/ClangImporter/Inputs/custom-modules/module.map @@ -175,3 +175,7 @@ module MacrosRedefB { module IndirectFields { header "IndirectFields.h" } + +module ObjCBridgeNonconforming { + header "ObjCBridgeNonconforming.h" +} diff --git a/test/ClangImporter/Inputs/frameworks/ImportAsMemberSubmodules.framework/Headers/Actual.h b/test/ClangImporter/Inputs/frameworks/ImportAsMemberSubmodules.framework/Headers/Actual.h new file mode 100644 index 00000000000..7e5a7469521 --- /dev/null +++ b/test/ClangImporter/Inputs/frameworks/ImportAsMemberSubmodules.framework/Headers/Actual.h @@ -0,0 +1,3 @@ +struct IAMOuter { int x; }; + +struct IAMInner { int y; }; diff --git a/test/ClangImporter/Inputs/frameworks/ImportAsMemberSubmodules.framework/Headers/Fwd.h b/test/ClangImporter/Inputs/frameworks/ImportAsMemberSubmodules.framework/Headers/Fwd.h new file mode 100644 index 00000000000..7b19ab30b6d --- /dev/null +++ b/test/ClangImporter/Inputs/frameworks/ImportAsMemberSubmodules.framework/Headers/Fwd.h @@ -0,0 +1,3 @@ +// The order of these forward-declarations affects whether there was a bug. +struct IAMOuter; +struct IAMInner; diff --git a/test/ClangImporter/Inputs/frameworks/ImportAsMemberSubmodules.framework/Headers/ImportAsMemberSubmodules.apinotes b/test/ClangImporter/Inputs/frameworks/ImportAsMemberSubmodules.framework/Headers/ImportAsMemberSubmodules.apinotes new file mode 100644 index 00000000000..4102842c2b0 --- /dev/null +++ b/test/ClangImporter/Inputs/frameworks/ImportAsMemberSubmodules.framework/Headers/ImportAsMemberSubmodules.apinotes @@ -0,0 +1,4 @@ +Name: ImportAsMemberSubmodules +Tags: +- Name: IAMInner + SwiftName: IAMOuter.Inner diff --git a/test/ClangImporter/Inputs/frameworks/ImportAsMemberSubmodules.framework/Headers/ImportAsMemberSubmodules.h b/test/ClangImporter/Inputs/frameworks/ImportAsMemberSubmodules.framework/Headers/ImportAsMemberSubmodules.h new file mode 100644 index 00000000000..e3164c60a8f --- /dev/null +++ b/test/ClangImporter/Inputs/frameworks/ImportAsMemberSubmodules.framework/Headers/ImportAsMemberSubmodules.h @@ -0,0 +1,3 @@ +// Umbrella header. +#import +#import diff --git a/test/ClangImporter/Inputs/frameworks/ImportAsMemberSubmodules.framework/Modules/module.modulemap b/test/ClangImporter/Inputs/frameworks/ImportAsMemberSubmodules.framework/Modules/module.modulemap new file mode 100644 index 00000000000..c4ab2d3d1a2 --- /dev/null +++ b/test/ClangImporter/Inputs/frameworks/ImportAsMemberSubmodules.framework/Modules/module.modulemap @@ -0,0 +1,5 @@ +framework module ImportAsMemberSubmodules { + umbrella header "ImportAsMemberSubmodules.h" + export * + module * { export * } +} diff --git a/test/ClangImporter/Inputs/typedef-with-generic-param.h b/test/ClangImporter/Inputs/typedef-with-generic-param.h new file mode 100644 index 00000000000..f6f69181042 --- /dev/null +++ b/test/ClangImporter/Inputs/typedef-with-generic-param.h @@ -0,0 +1,9 @@ +#import + +@interface Foo <__covariant T> +typedef void (^CompletionBlock)(T _Nullable result, NSError *_Nullable error); +@end + +@interface Foo (Convenience) ++ (Foo *)fooWithCompletionBlock: (void (^)(CompletionBlock adapter))block; +@end diff --git a/test/ClangImporter/availability_open_enums.swift b/test/ClangImporter/availability_open_enums.swift new file mode 100644 index 00000000000..402c14d9955 --- /dev/null +++ b/test/ClangImporter/availability_open_enums.swift @@ -0,0 +1,18 @@ +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify -I %S/Inputs/custom-modules -swift-version 4 %s + +// REQUIRES: objc_interop + +import Foundation +import AvailabilityExtras + +func exhaustiveSwitch(e: NSEnumAddedCasesIn2017) { + switch e { // expected-error{{switch must be exhaustive}} + // expected-note@-1{{add missing case: '.newCaseOne'}} + case .existingCaseOne: + return + case .existingCaseTwo: + return + case .existingCaseThree: + return + } +} \ No newline at end of file diff --git a/test/ClangImporter/availability_open_enums_swift3.swift b/test/ClangImporter/availability_open_enums_swift3.swift new file mode 100644 index 00000000000..4ff7402b37d --- /dev/null +++ b/test/ClangImporter/availability_open_enums_swift3.swift @@ -0,0 +1,18 @@ +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify -I %S/Inputs/custom-modules -swift-version 3 %s + +// REQUIRES: objc_interop + +import Foundation +import AvailabilityExtras + +func exhaustiveSwitch(e: NSEnumAddedCasesIn2017) { + switch e { // expected-warning{{switch must be exhaustive}} + // expected-note@-1{{add missing case: '.newCaseOne'}} + case .existingCaseOne: + return + case .existingCaseTwo: + return + case .existingCaseThree: + return + } +} \ No newline at end of file diff --git a/test/ClangImporter/enum-error.swift b/test/ClangImporter/enum-error.swift index babf82f934d..adb476bc52a 100644 --- a/test/ClangImporter/enum-error.swift +++ b/test/ClangImporter/enum-error.swift @@ -1,14 +1,14 @@ // REQUIRES: OS=macosx -// RUN: %target-swift-frontend -DVALUE -emit-sil %s -import-objc-header %S/Inputs/enum-error.h | %FileCheck %s -check-prefix=VALUE -// RUN: %target-swift-frontend -DEMPTYCATCH -emit-sil %s -import-objc-header %S/Inputs/enum-error.h | %FileCheck %s -check-prefix=EMPTYCATCH -// RUN: %target-swift-frontend -DASQEXPR -emit-sil %s -import-objc-header %S/Inputs/enum-error.h | %FileCheck %s -check-prefix=ASQEXPR -// RUN: %target-swift-frontend -DASBANGEXPR -emit-sil %s -import-objc-header %S/Inputs/enum-error.h | %FileCheck %s -check-prefix=ASBANGEXPR -// RUN: %target-swift-frontend -DCATCHIS -emit-sil %s -import-objc-header %S/Inputs/enum-error.h | %FileCheck %s -check-prefix=CATCHIS -// RUN: %target-swift-frontend -DCATCHAS -emit-sil %s -import-objc-header %S/Inputs/enum-error.h | %FileCheck %s -check-prefix=CATCHAS -// RUN: %target-swift-frontend -DGENERICONLY -emit-sil %s -import-objc-header %S/Inputs/enum-error.h | %FileCheck %s -check-prefix=GENERICONLY +// RUN: %target-swift-frontend -DVALUE -emit-sil -sil-serialize-witness-tables %s -import-objc-header %S/Inputs/enum-error.h | %FileCheck %s -check-prefix=VALUE +// RUN: %target-swift-frontend -DEMPTYCATCH -emit-sil -sil-serialize-witness-tables %s -import-objc-header %S/Inputs/enum-error.h | %FileCheck %s -check-prefix=EMPTYCATCH +// RUN: %target-swift-frontend -DASQEXPR -emit-sil -sil-serialize-witness-tables %s -import-objc-header %S/Inputs/enum-error.h | %FileCheck %s -check-prefix=ASQEXPR +// RUN: %target-swift-frontend -DASBANGEXPR -emit-sil -sil-serialize-witness-tables %s -import-objc-header %S/Inputs/enum-error.h | %FileCheck %s -check-prefix=ASBANGEXPR +// RUN: %target-swift-frontend -DCATCHIS -emit-sil -sil-serialize-witness-tables %s -import-objc-header %S/Inputs/enum-error.h | %FileCheck %s -check-prefix=CATCHIS +// RUN: %target-swift-frontend -DCATCHAS -emit-sil -sil-serialize-witness-tables %s -import-objc-header %S/Inputs/enum-error.h | %FileCheck %s -check-prefix=CATCHAS +// RUN: %target-swift-frontend -DGENERICONLY -emit-sil -sil-serialize-witness-tables %s -import-objc-header %S/Inputs/enum-error.h | %FileCheck %s -check-prefix=GENERICONLY -// RUN: not %target-swift-frontend -DEXHAUSTIVE -emit-sil %s -import-objc-header %S/Inputs/enum-error.h 2>&1 | %FileCheck %s -check-prefix=EXHAUSTIVE +// RUN: not %target-swift-frontend -DEXHAUSTIVE -emit-sil -sil-serialize-witness-tables %s -import-objc-header %S/Inputs/enum-error.h 2>&1 | %FileCheck %s -check-prefix=EXHAUSTIVE // RUN: %target-swift-frontend -typecheck %s -import-objc-header %S/Inputs/enum-error.h -DERRORS -verify // RUN: echo '#include "enum-error.h"' > %t.m diff --git a/test/ClangImporter/import-as-member.swift b/test/ClangImporter/import-as-member.swift new file mode 100644 index 00000000000..33bd4017c49 --- /dev/null +++ b/test/ClangImporter/import-as-member.swift @@ -0,0 +1,5 @@ +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -F %S/Inputs/frameworks %s -verify + +import ImportAsMemberSubmodules + +let _: IAMOuter.Inner? diff --git a/test/ClangImporter/objc_bridging_generics.swift b/test/ClangImporter/objc_bridging_generics.swift index 6daa42dc661..6e15c0db326 100644 --- a/test/ClangImporter/objc_bridging_generics.swift +++ b/test/ClangImporter/objc_bridging_generics.swift @@ -1,9 +1,10 @@ -// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -parse-as-library -verify -swift-version 4 %s +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -parse-as-library -verify -swift-version 4 -I %S/Inputs/custom-modules %s // REQUIRES: objc_interop import Foundation import objc_generics +import ObjCBridgeNonconforming func testNSArrayBridging(_ hive: Hive) { _ = hive.bees as [Bee] @@ -392,3 +393,8 @@ let third: Third! = Third() func useThird() { _ = third.description } + + +func testNonconforming(bnc: ObjCBridgeNonconforming) { + let _: Int = bnc.foo // expected-error{{cannot convert value of type 'Set' to specified type 'Int'}} +} diff --git a/test/ClangImporter/objc_parse.swift b/test/ClangImporter/objc_parse.swift index 370a0777bbb..5781c2c976d 100644 --- a/test/ClangImporter/objc_parse.swift +++ b/test/ClangImporter/objc_parse.swift @@ -492,7 +492,7 @@ class IncompleteProtocolAdopter : Incomplete, IncompleteOptional { // expected-e func testNullarySelectorPieces(_ obj: AnyObject) { obj.foo(1, bar: 2, 3) // no-warning - obj.foo(1, 2, bar: 3) // expected-error{{cannot call value of non-function type 'Any?!'}} + obj.foo(1, 2, bar: 3) // expected-error{{cannot invoke 'foo' with an argument list of type '(Int, Int, bar: Int)'}} } func testFactoryMethodAvailability() { diff --git a/test/ClangImporter/typedef_with_generic_param.swift b/test/ClangImporter/typedef_with_generic_param.swift new file mode 100644 index 00000000000..e80973a92e4 --- /dev/null +++ b/test/ClangImporter/typedef_with_generic_param.swift @@ -0,0 +1,10 @@ +// RUN: %target-swift-frontend -typecheck %s -import-objc-header %S/Inputs/typedef-with-generic-param.h 2>&1 + +// REQUIRES: OS=macosx + +typealias Result = (T?, Error?) +typealias Handler = (Result) -> Void + +func foo(_ handler: Handler?) {} + +let _ = Foo(completionBlock: foo) diff --git a/test/Compatibility/enum_cases.swift b/test/Compatibility/enum_cases.swift index 25cbfaf321a..100bf58726c 100644 --- a/test/Compatibility/enum_cases.swift +++ b/test/Compatibility/enum_cases.swift @@ -89,3 +89,16 @@ enum Foo { func foo(_: T, _: T) {} foo(Foo.a, Foo.b) // expected-error {{cannot invoke 'foo' with an argument list of type '((Int) -> Foo, (Int) -> Foo)}} // expected-note@-1 {{expected an argument list of type '(T, T)'}} + +// rdar://problem/32551313 - Useless SE-0110 diagnostic (only in Swift 4 mode) + +enum E_32551313 { + case Left(L) + case Right(R) +} + +struct Foo_32551313 { + static func bar() -> E_32551313<(String, Foo_32551313?), (String, String)>? { + return E_32551313.Left("", Foo_32551313()) // Ok + } +} diff --git a/test/Compatibility/self_same_type.swift b/test/Compatibility/self_same_type.swift index 55871749989..1865fbb54a4 100644 --- a/test/Compatibility/self_same_type.swift +++ b/test/Compatibility/self_same_type.swift @@ -1,5 +1,10 @@ // RUN: %target-typecheck-verify-swift -swift-version 3 +// Note: while Swift 3.2 originally intended to provide backward +// compatibility here, the type-soundness issue was considered so severe +// (due to it breaking the optimizer) that that we escalated it to an +// error. + protocol P { associatedtype T } @@ -9,7 +14,7 @@ protocol Q { } class C1: Q { - func foo(_: T, _: C1) where T.T == C1 {} // expected-warning{{instance method 'foo' in non-final class 'C1' cannot be used to satisfy requirement instance method 'foo' (in protocol 'Q') due to same-type requirement involving 'Self'}}}} + func foo(_: T, _: C1) where T.T == C1 {} // expected-error{{instance method 'foo' in non-final class 'C1' cannot be used to satisfy requirement instance method 'foo' (in protocol 'Q') due to same-type requirement involving 'Self'}}}} // expected-note@-1{{consider weakening the same-type requirement 'T.T' == 'C1' to a superclass requirement}}{{41-43=:}} } diff --git a/test/Compatibility/tuple_arguments.swift b/test/Compatibility/tuple_arguments.swift index aa7ddf53c53..fd64d56207b 100644 --- a/test/Compatibility/tuple_arguments.swift +++ b/test/Compatibility/tuple_arguments.swift @@ -1154,7 +1154,7 @@ do { _ = GenericEnum.two(3, 4) _ = GenericEnum.two((3, 4)) // expected-error {{missing argument for parameter #2 in call}} - _ = GenericEnum.tuple(3, 4) // expected-error {{enum element 'tuple' expects a single parameter of type '(_, _)'}} {{25-25=(}} {{29-29=)}} + _ = GenericEnum.tuple(3, 4) // expected-error {{enum element 'tuple' expects a single parameter of type '(T, T)'}} {{25-25=(}} {{29-29=)}} _ = GenericEnum.tuple((3, 4)) } @@ -1187,7 +1187,7 @@ do { _ = GenericEnum.two((a, b)) // expected-error {{missing argument for parameter #2 in call}} _ = GenericEnum.two(c) // expected-error {{missing argument for parameter #2 in call}} - _ = GenericEnum.tuple(a, b) // expected-error {{enum element 'tuple' expects a single parameter of type '(_, _)'}} {{25-25=(}} {{29-29=)}} + _ = GenericEnum.tuple(a, b) // expected-error {{enum element 'tuple' expects a single parameter of type '(T, T)'}} {{25-25=(}} {{29-29=)}} _ = GenericEnum.tuple((a, b)) _ = GenericEnum.tuple(c) } @@ -1223,7 +1223,7 @@ do { _ = GenericEnum.two((a, b)) // expected-error {{missing argument for parameter #2 in call}} _ = GenericEnum.two(c) // expected-error {{missing argument for parameter #2 in call}} - _ = GenericEnum.tuple(a, b) // expected-error {{enum element 'tuple' expects a single parameter of type '(_, _)'}} {{25-25=(}} {{29-29=)}} + _ = GenericEnum.tuple(a, b) // expected-error {{enum element 'tuple' expects a single parameter of type '(T, T)'}} {{25-25=(}} {{29-29=)}} _ = GenericEnum.tuple((a, b)) _ = GenericEnum.tuple(c) } @@ -1460,7 +1460,7 @@ enum DataSourcePage { } let pages1: MutableProperty<(data: DataSourcePage, totalCount: Int)> = MutableProperty(( - // expected-error@-1 {{cannot convert value of type 'MutableProperty<(data: _, totalCount: Int)>' to specified type 'MutableProperty<(data: DataSourcePage, totalCount: Int)>'}} + // expected-error@-1 {{expression type 'MutableProperty<(data: DataSourcePage, totalCount: Int)>' is ambiguous without more context}} data: .notLoaded, totalCount: 0 )) diff --git a/test/Constraints/array_literal.swift b/test/Constraints/array_literal.swift index 91c624b2056..684a9ce6263 100644 --- a/test/Constraints/array_literal.swift +++ b/test/Constraints/array_literal.swift @@ -50,7 +50,7 @@ useDoubleList([1.0,2,3]) useDoubleList([1.0,2.0,3.0]) useIntDict(["Niners" => 31, "Ravens" => 34]) -useIntDict(["Niners" => 31, "Ravens" => 34.0]) // expected-error{{cannot convert value of type 'Double' to expected argument type 'Int'}} +useIntDict(["Niners" => 31, "Ravens" => 34.0]) // expected-error{{cannot convert value of type '(String, Double)' to expected element type '(String, Int)'}} // QoI: Propagate contextual information in a call to operands useDoubleDict(["Niners" => 31, "Ravens" => 34.0]) useDoubleDict(["Niners" => 31.0, "Ravens" => 34]) diff --git a/test/Constraints/closures.swift b/test/Constraints/closures.swift index bfb7424386b..6108a15334f 100644 --- a/test/Constraints/closures.swift +++ b/test/Constraints/closures.swift @@ -366,8 +366,7 @@ func rdar20868864(_ s: String) { func r22058555() { var firstChar: UInt8 = 0 "abc".withCString { chars in - // FIXME https://bugs.swift.org/browse/SR-4836: was {{cannot assign value of type 'Int8' to type 'UInt8'}} - firstChar = chars[0] // expected-error {{cannot subscript a value of incorrect or ambiguous type}} + firstChar = chars[0] // expected-error {{cannot assign value of type 'Int8' to type 'UInt8'}} } } @@ -529,3 +528,30 @@ r32432145 { _,_ in // expected-error@-1 {{contextual closure type '() -> ()' expects 0 arguments, but 2 were used in closure body}} {{13-19=}} print("answer is 42") } + +// rdar://problem/30106822 - Swift ignores type error in closure and presents a bogus error about the caller +[1, 2].first { $0.foo = 3 } +// expected-error@-1 {{value of type 'Int' has no member 'foo'}} + +// rdar://problem/32433193, SR-5030 - Higher-order function diagnostic mentions the wrong contextual type conversion problem +protocol A_SR_5030 { + associatedtype Value + func map(_ t : @escaping (Self.Value) -> U) -> B_SR_5030 +} + +struct B_SR_5030 : A_SR_5030 { + typealias Value = T + func map(_ t : @escaping (T) -> U) -> B_SR_5030 { fatalError() } +} + +func sr5030_exFalso() -> T { + fatalError() +} + +extension A_SR_5030 { + func foo() -> B_SR_5030 { + let tt : B_SR_5030 = sr5030_exFalso() + return tt.map { x in (idx: x) } + // expected-error@-1 {{cannot convert value of type '(idx: (Int))' to closure result type 'Int'}} + } +} diff --git a/test/Constraints/construction.swift b/test/Constraints/construction.swift index 834eff8098f..98c98903cf2 100644 --- a/test/Constraints/construction.swift +++ b/test/Constraints/construction.swift @@ -152,3 +152,20 @@ extension S3 { } let s3b = S3(maybe: s3a) + +// SR-5245 - Erroneous diagnostic - Type of expression is ambiguous without more context +class SR_5245 { + struct S { + enum E { + case e1 + case e2 + } + + let e: [E] + } + + init(s: S) {} +} + +SR_5245(s: SR_5245.S(f: [.e1, .e2])) +// expected-error@-1 {{incorrect argument label in call (have 'f:', expected 'e:')}} {{22-23=e}} diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index 8a1cbb8127b..fd58398ff2e 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -983,3 +983,80 @@ let _: KeyPath = \R32101765.prop32101765.unknown for var i in 0..<10 { // expected-warning {{variable 'i' was never mutated; consider changing to 'let' constant}} {{5-9=}} _ = i + 1 } + +// rdar://problem/32726044 - shrink reduced domains too far + +public protocol P_32726044 {} + +extension Int: P_32726044 {} +extension Float: P_32726044 {} + +public func *(lhs: P_32726044, rhs: P_32726044) -> Double { + fatalError() +} + +func rdar32726044() -> Float { + var f: Float = 0 + f = Float(1) * 100 // Ok + let _: Float = Float(42) + 0 // Ok + return f +} + +// SR-5045 - Attempting to return result of reduce(_:_:) in a method with no return produces ambiguous error +func sr5045() { + let doubles: [Double] = [1, 2, 3] + return doubles.reduce(0, +) + // expected-error@-1 {{unexpected non-void return value in void function}} +} + +// rdar://problem/32934129 - QoI: misleading diagnostic +class L_32934129 { + init(_ value: T) { self.value = value } + init(_ value: T, _ next: L_32934129?) { + self.value = value + self.next = next + } + + var value: T + var next: L_32934129? = nil + + func length() -> Int { + func inner(_ list: L_32934129?, _ count: Int) { + guard let list = list else { return count } // expected-error {{unexpected non-void return value in void function}} + return inner(list.next, count + 1) + } + + return inner(self, 0) // expected-error {{cannot convert return expression of type '()' to return type 'Int'}} + } +} + +// rdar://problem/31671195 - QoI: erroneous diagnostic - cannot call value of non-function type + +class C_31671195 { + var name: Int { fatalError() } + func name(_: Int) { fatalError() } +} +C_31671195().name(UInt(0)) +// expected-error@-1 {{cannot convert value of type 'UInt' to expected argument type 'Int'}} + + +// rdar://problem/28456467 - QoI: erroneous diagnostic - cannot call value of non-function type + +class AST_28456467 { + var hasStateDef: Bool { return false } +} + +protocol Expr_28456467 {} + +class ListExpr_28456467 : AST_28456467, Expr_28456467 { + let elems: [Expr_28456467] + + init(_ elems:[Expr_28456467] ) { + self.elems = elems + } + + override var hasStateDef: Bool { + return elems.first(where: { $0.hasStateDef }) != nil + // expected-error@-1 {{value of type 'Expr_28456467' has no member 'hasStateDef'}} + } +} diff --git a/test/Constraints/diagnostics_swift4.swift b/test/Constraints/diagnostics_swift4.swift index c90f80aaa32..290b3885f5b 100644 --- a/test/Constraints/diagnostics_swift4.swift +++ b/test/Constraints/diagnostics_swift4.swift @@ -39,9 +39,13 @@ func foo() -> R31898542<()> { // rdar://problem/31973368 - Cannot convert value of type '(K, V) -> ()' to expected argument type '((key: _, value: _)) -> Void' +// SE-0110: We reverted to allowing this for the time being, but this +// test is valuable in case we end up disallowing it again in the +// future. + class R { func forEach(_ body: (K, V) -> ()) { - var dict: [K:V] = [:] - dict.forEach(body) // expected-error {{nested tuple parameter '(key: K, value: V)' of function '(((key: K, value: V)) throws -> Void) throws -> ()' does not support destructuring}} + let dict: [K:V] = [:] + dict.forEach(body) } } diff --git a/test/Constraints/enum_cases.swift b/test/Constraints/enum_cases.swift index 6ba2924e4a7..9bf6b1c3d71 100644 --- a/test/Constraints/enum_cases.swift +++ b/test/Constraints/enum_cases.swift @@ -41,7 +41,10 @@ func bar_3(_: (T) -> G_E) {} bar_1(E.foo) // Ok bar_1(E.bar) // Ok -bar_1(E.two) // expected-error {{cannot convert value of type '(Int, Int) -> E' to expected argument type '(_) -> E'}} +// SE-0110: We reverted to allowing this for the time being, but this +// test is valuable in case we end up disallowing it again in the +// future. +bar_1(E.two) // Ok since we backed off on this aspect of SE-0110 for the moment. bar_1(E.tuple) // Ok - it's going to be ((x: Int, y: Int)) bar_2(G_E.foo) // Ok @@ -86,3 +89,16 @@ enum Foo { func foo(_: T, _: T) {} foo(Foo.a, Foo.b) // Ok in Swift 4 because we strip labels from the arguments + +// rdar://problem/32551313 - Useless SE-0110 diagnostic + +enum E_32551313 { + case Left(L) + case Right(R) +} + +struct Foo_32551313 { + static func bar() -> E_32551313<(String, Foo_32551313?), (String, String)>? { + return E_32551313.Left("", Foo_32551313()) // expected-error {{extra argument in call}} + } +} diff --git a/test/Constraints/fixes.swift b/test/Constraints/fixes.swift index a9b049fe0ce..8791972e638 100644 --- a/test/Constraints/fixes.swift +++ b/test/Constraints/fixes.swift @@ -143,4 +143,4 @@ struct S1116 { } let a1116: [S1116] = [] -var s1116 = Set(1...10).subtracting(a1116.map({ $0.s })) // expected-error {{'map' produces '[T]', not the expected contextual result type 'Set'}} +var s1116 = Set(1...10).subtracting(a1116.map({ $0.s })) // expected-error {{cannot convert value of type '[Int?]' to expected argument type 'Set'}} diff --git a/test/Constraints/function.swift b/test/Constraints/function.swift index 6aeb021a803..d6e661cebd2 100644 --- a/test/Constraints/function.swift +++ b/test/Constraints/function.swift @@ -90,12 +90,12 @@ private class SR2657BlockClass { init(f: T) { self.f = f } } -func foo(block: () -> ()) { +func foo(block: () -> ()) { // expected-note 2 {{parameter 'block' is implicitly non-escaping}} let a = SR2657BlockClass(f: block) // No error let b = SR2657BlockClass<()->()>(f: block) - // expected-error@-1 {{invalid conversion from non-escaping function of type '() -> ()' to potentially escaping function type '() -> ()'}} + // expected-error@-1 {{passing non-escaping parameter 'block' to function expecting an @escaping closure}} let c: SR2657BlockClass<()->()> = SR2657BlockClass(f: block) // expected-error@-1 {{cannot convert value of type 'SR2657BlockClass<() -> ()>' to specified type 'SR2657BlockClass<() -> ()>'}} let d: SR2657BlockClass<()->()> = SR2657BlockClass<()->()>(f: block) - // expected-error@-1 {{invalid conversion from non-escaping function of type '() -> ()' to potentially escaping function type '() -> ()'}} + // expected-error@-1 {{passing non-escaping parameter 'block' to function expecting an @escaping closure}} } diff --git a/test/Constraints/gather_all_adjacencies.swift b/test/Constraints/gather_all_adjacencies.swift new file mode 100644 index 00000000000..b4587dd351d --- /dev/null +++ b/test/Constraints/gather_all_adjacencies.swift @@ -0,0 +1,38 @@ +// RUN: %target-swift-frontend -typecheck %s + +// SR-5120 / rdar://problem/32618740 +protocol InitCollection: Collection { + init(_ array: [Iterator.Element]) +} + +protocol InitAny { + init() +} + +extension Array: InitCollection { + init(_ array: [Iterator.Element]) { + self = array + } +} + +extension String: InitAny { + init() { + self = "bar" + } +} + +class Foo { + func foo(of type: U.Type) -> T + where T.Iterator.Element == U + { + return T.init([U.init()]) + } + + func foo(of type: U.Type) -> T? + where T.Iterator.Element == U + { + return T.init([U.init()]) + } +} + +let _: [String] = Foo().foo(of: String.self) diff --git a/test/Constraints/members.swift b/test/Constraints/members.swift index 09bf137fa21..7f7ddaa150d 100644 --- a/test/Constraints/members.swift +++ b/test/Constraints/members.swift @@ -390,3 +390,30 @@ func r25341015_inner() { func r25341015_local() {} r25341015_local(x: 1, y: 2) // expected-error {{argument passed to call that takes no arguments}} } + +// rdar://problem/32854314 - Emit shadowing diagnostics even if argument types do not much completely + +func foo_32854314() -> Double { + return 42 +} + +func bar_32854314() -> Int { + return 0 +} + +extension Array where Element == Int { + func foo() { + let _ = min(foo_32854314(), bar_32854314()) // expected-note {{use 'Swift.' to reference the global function in module 'Swift'}} {{13-13=Swift.}} + // expected-error@-1 {{use of 'min' nearly matches global function 'min' in module 'Swift' rather than instance method 'min()'}} + } + + func foo(_ x: Int, _ y: Double) { + let _ = min(x, y) // expected-note {{use 'Swift.' to reference the global function in module 'Swift'}} {{13-13=Swift.}} + // expected-error@-1 {{use of 'min' nearly matches global function 'min' in module 'Swift' rather than instance method 'min()'}} + } + + func bar() { + let _ = min(1.0, 2) // expected-note {{use 'Swift.' to reference the global function in module 'Swift'}} {{13-13=Swift.}} + // expected-error@-1 {{use of 'min' nearly matches global function 'min' in module 'Swift' rather than instance method 'min()'}} + } +} diff --git a/test/Constraints/same_types.swift b/test/Constraints/same_types.swift index ff56973fa27..b22ae3bfb69 100644 --- a/test/Constraints/same_types.swift +++ b/test/Constraints/same_types.swift @@ -58,14 +58,16 @@ func test3(_ t: T, u: U) -> (X, X) func fail1< T: Fooable, U: Fooable >(_ t: T, u: U) -> (X, Y) - where T.Foo == X, U.Foo == Y, T.Foo == U.Foo { // expected-error{{associated type 'T.Foo' cannot be equal to both 'X' and 'Y'}} + where T.Foo == X, U.Foo == Y, T.Foo == U.Foo { // expected-error{{'U.Foo' cannot be equal to both 'Y' and 'X'}} + // expected-note@-1{{same-type constraint 'T.Foo' == 'X' written here}} return (t.foo, u.foo) // expected-error{{cannot convert return expression of type 'X' to return type 'Y'}} } func fail2< T: Fooable, U: Fooable >(_ t: T, u: U) -> (X, Y) - where T.Foo == U.Foo, T.Foo == X, U.Foo == Y { // expected-error{{associated type 'U.Foo' cannot be equal to both 'X' and 'Y'}} + where T.Foo == U.Foo, T.Foo == X, U.Foo == Y { // expected-error{{'U.Foo' cannot be equal to both 'Y' and 'X'}} + // expected-note@-1{{same-type constraint 'T.Foo' == 'X' written here}} return (t.foo, u.foo) // expected-error{{cannot convert return expression of type 'X' to return type 'Y'}} } @@ -75,7 +77,7 @@ func test4(_ t: T) -> Y where T.Bar == Y { func fail3(_ t: T) -> X where T.Bar == X { // expected-error {{'X' does not conform to required protocol 'Fooable'}} - return t.bar + return t.bar // expected-error{{cannot convert return expression of type 'T.Bar' }} } func test5(_ t: T) -> X where T.Bar.Foo == X { @@ -88,25 +90,28 @@ func test6(_ t: T) -> (Y, X) where T.Bar == Y { func test7(_ t: T) -> (Y, X) where T.Bar == Y, T.Bar.Foo == X { // expected-warning@-1{{redundant same-type constraint 'T.Bar.Foo' == 'X'}} + // expected-note@-2{{same-type constraint 'T.Bar.Foo' == 'Y.Foo' (aka 'X') implied here}} return (t.bar, t.bar.foo) } func fail4(_ t: T) -> (Y, Z) where - T.Bar == Y, - T.Bar.Foo == Z { // expected-error{{associated type 'T.Bar.Foo' cannot be equal to both 'Y.Foo' (aka 'X') and 'Z'}} + T.Bar == Y, // expected-note{{same-type constraint 'T.Bar.Foo' == 'Y.Foo' (aka 'X') implied here}} + T.Bar.Foo == Z { // expected-error{{'T.Bar.Foo' cannot be equal to both 'Z' and 'Y.Foo' (aka 'X')}} return (t.bar, t.bar.foo) // expected-error{{cannot convert return expression of type 'X' to return type 'Z'}} } func fail5(_ t: T) -> (Y, Z) where - T.Bar.Foo == Z, // expected-warning{{redundant same-type constraint 'T.Bar.Foo' == 'Z'}} - T.Bar == Y { // expected-error{{associated type 'T.Bar.Foo' cannot be equal to both 'Z' and 'X'}} - // expected-note@-1{{same-type constraint 'T.Bar.Foo' == 'Y.Foo' (aka 'X') implied here}} + T.Bar.Foo == Z, // expected-note{{same-type constraint 'T.Bar.Foo' == 'Z' written here}} + T.Bar == Y { // expected-error{{'T.Bar.Foo' cannot be equal to both 'Y.Foo' (aka 'X') and 'Z'}} return (t.bar, t.bar.foo) // expected-error{{cannot convert return expression of type 'X' to return type 'Z'}} } -func test8(_ t: T) where T.Foo == X, T.Foo == Y {} // expected-error{{associated type 'T.Foo' cannot be equal to both 'X' and 'Y'}} +func test8(_ t: T) + where T.Foo == X, // expected-note{{same-type constraint 'T.Foo' == 'X' written here}} + T.Foo == Y {} // expected-error{{'T.Foo' cannot be equal to both 'Y' and 'X'}} + func testAssocTypeEquivalence(_ fooable: T) -> X.Type where T.Foo == X { @@ -118,16 +123,24 @@ func fail6(_ t: T) -> Int where T == Int { // expected-error{{same-type requi } func test8(_ t: T, u: U) -> (Y, Y, X, X) - where T.Bar == Y, U.Bar.Foo == X, T.Bar == U.Bar { // expected-warning{{redundant same-type constraint 'U.Bar.Foo' == 'X'}} + where T.Bar == Y, // expected-note{{same-type constraint 'U.Bar.Foo' == 'Y.Foo' (aka 'X') implied here}} + U.Bar.Foo == X, T.Bar == U.Bar { // expected-warning{{redundant same-type constraint 'U.Bar.Foo' == 'X'}} return (t.bar, u.bar, t.bar.foo, u.bar.foo) } func test8a(_ t: T, u: U) -> (Y, Y, X, X) where - T.Bar == Y, U.Bar.Foo == X, U.Bar == T.Bar { // expected-warning{{redundant same-type constraint 'U.Bar.Foo' == 'X'}} + T.Bar == Y, // expected-note{{same-type constraint 'U.Bar.Foo' == 'Y.Foo' (aka 'X') implied here}} + U.Bar.Foo == X, U.Bar == T.Bar { // expected-warning{{redundant same-type constraint 'U.Bar.Foo' == 'X'}} return (t.bar, u.bar, t.bar.foo, u.bar.foo) } +func test8b(_ t: T, u: U) + where U.Bar.Foo == X, // expected-warning{{redundant same-type constraint 'U.Bar.Foo' == 'X'}} + T.Bar == Y, // expected-note{{same-type constraint 'U.Bar.Foo' == 'Y.Foo' (aka 'X') implied here}} + T.Bar == U.Bar { +} + // rdar://problem/19137463 func rdar19137463(_ t: T) where T.a == T {} // expected-error{{'a' is not a member type of 'T'}} rdar19137463(1) @@ -237,6 +250,34 @@ func structuralSameTypeRecursive1(_: T, _: U) where T.Assoc1 == Tuple2 // expected-error{{same-type constraint 'T.Assoc1' == '(T.Assoc1, U)' is recursive}} { } +protocol P3 { +} + +protocol P4 { + associatedtype A +} + +func test9(_: T) where T.A == X, T: P4, T.A: P3 { } // expected-error{{same-type constraint type 'X' does not conform to required protocol 'P3'}} + +// Same-type constraint conflict through protocol where clauses. +protocol P5 where Foo1 == Foo2 { + associatedtype Foo1 + associatedtype Foo2 +} + +protocol P6 { + associatedtype Bar: P5 +} + +struct X5a {} + +struct X5b { } + +func test9(_ t: T, u: U) + where T.Bar.Foo1 == X5a, // expected-note{{same-type constraint 'T.Bar.Foo1' == 'X5a' written here}} + U.Bar.Foo2 == X5b, // expected-error{{'U.Bar.Foo2' cannot be equal to both 'X5b' and 'X5a'}} + T.Bar == U.Bar { +} // FIXME: Remove -verify-ignore-unknown. // :0: error: unexpected error produced: generic parameter τ_0_0.Bar.Foo cannot be equal to both 'Y.Foo' (aka 'X') and 'Z' diff --git a/test/Constraints/trailing_closures_objc.swift b/test/Constraints/trailing_closures_objc.swift new file mode 100644 index 00000000000..ecea125f891 --- /dev/null +++ b/test/Constraints/trailing_closures_objc.swift @@ -0,0 +1,29 @@ +// RUN: %target-swift-frontend -typecheck -verify %s + +// REQUIRES: objc_interop +// REQUIRES: OS=macosx + +import Foundation +import AVFoundation +import AppKit + +func foo(options: [AVMediaSelectionOption]) { + let menuItems: [NSMenuItem] = options.map { (option: AVMediaSelectionOption) in + NSMenuItem(title: option.displayName, action: #selector(NSViewController.respondToMediaOptionSelection(from:)), keyEquivalent: "") + // expected-error@-1 {{type 'NSViewController' has no member 'respondToMediaOptionSelection(from:)'}} + } +} + +func rdar28004686(a: [IndexPath]) { + _ = a.sorted { (lhs: NSIndexPath, rhs: NSIndexPath) -> Bool in true } + // expected-error@-1 {{'NSIndexPath' is not convertible to 'IndexPath'}} +} + +class Test: NSObject { + var categories : NSArray? + func rdar28012273() { + let categories = ["hello", "world"] + self.categories = categories.sorted { $0.localizedCaseInsensitiveCompare($1) == ComparisonResult.orderedDescending } + // expected-error@-1 {{cannot assign value of type '[String]' to type 'NSArray?'}} {{121-121= as NSArray}} + } +} diff --git a/test/Constraints/tuple_arguments.swift b/test/Constraints/tuple_arguments.swift index 5df2266c8e7..ae75e2b6af6 100644 --- a/test/Constraints/tuple_arguments.swift +++ b/test/Constraints/tuple_arguments.swift @@ -1135,7 +1135,7 @@ do { _ = GenericEnum.two(3, 4) _ = GenericEnum.two((3, 4)) // expected-error {{missing argument for parameter #2 in call}} - _ = GenericEnum.tuple(3, 4) // expected-error {{enum element 'tuple' expects a single parameter of type '(_, _)'}} {{25-25=(}} {{29-29=)}} + _ = GenericEnum.tuple(3, 4) // expected-error {{enum element 'tuple' expects a single parameter of type '(T, T)'}} {{25-25=(}} {{29-29=)}} _ = GenericEnum.tuple((3, 4)) } @@ -1168,7 +1168,7 @@ do { _ = GenericEnum.two((a, b)) // expected-error {{missing argument for parameter #2 in call}} _ = GenericEnum.two(c) // expected-error {{missing argument for parameter #2 in call}} - _ = GenericEnum.tuple(a, b) // expected-error {{enum element 'tuple' expects a single parameter of type '(_, _)'}} {{25-25=(}} {{29-29=)}} + _ = GenericEnum.tuple(a, b) // expected-error {{enum element 'tuple' expects a single parameter of type '(T, T)'}} {{25-25=(}} {{29-29=)}} _ = GenericEnum.tuple((a, b)) _ = GenericEnum.tuple(c) } @@ -1204,7 +1204,7 @@ do { _ = GenericEnum.two((a, b)) // expected-error {{missing argument for parameter #2 in call}} _ = GenericEnum.two(c) // expected-error {{missing argument for parameter #2 in call}} - _ = GenericEnum.tuple(a, b) // expected-error {{enum element 'tuple' expects a single parameter of type '(_, _)'}} {{25-25=(}} {{29-29=)}} + _ = GenericEnum.tuple(a, b) // expected-error {{enum element 'tuple' expects a single parameter of type '(T, T)'}} {{25-25=(}} {{29-29=)}} _ = GenericEnum.tuple((a, b)) _ = GenericEnum.tuple(c) } @@ -1338,17 +1338,17 @@ do { s.takesClosureTuple({ _ = $0 }) s.takesClosureTuple({ x in }) s.takesClosureTuple({ (x: (Double, Double)) in }) - s.takesClosureTuple({ _ = $0; _ = $1 }) // expected-error {{closure tuple parameter '(Double, Double)' does not support destructuring with implicit parameters}} - s.takesClosureTuple({ (x, y) in }) // expected-error {{closure tuple parameter '(Double, Double)' does not support destructuring}} {{25-31=(arg)}} {{34-34=let (x, y) = arg; }} - s.takesClosureTuple({ (x: Double, y:Double) in }) // expected-error {{closure tuple parameter '(Double, Double)' does not support destructuring}} {{25-46=(arg: (Double, Double))}} {{49-49=let (x, y) = arg; }} + s.takesClosureTuple({ _ = $0; _ = $1 }) + s.takesClosureTuple({ (x, y) in }) + s.takesClosureTuple({ (x: Double, y:Double) in }) let sTwo = GenericConforms<(Double, Double)>() sTwo.takesClosure({ _ = $0 }) sTwo.takesClosure({ x in }) sTwo.takesClosure({ (x: (Double, Double)) in }) - sTwo.takesClosure({ _ = $0; _ = $1 }) // expected-error {{closure tuple parameter '(Double, Double)' does not support destructuring with implicit parameters}} - sTwo.takesClosure({ (x, y) in }) // expected-error {{closure tuple parameter '(Double, Double)' does not support destructuring}} {{23-29=(arg)}} {{32-32=let (x, y) = arg; }} - sTwo.takesClosure({ (x: Double, y: Double) in }) // expected-error {{closure tuple parameter '(Double, Double)' does not support destructuring}} {{23-45=(arg: (Double, Double))}} {{48-48=let (x, y) = arg; }} + sTwo.takesClosure({ _ = $0; _ = $1 }) + sTwo.takesClosure({ (x, y) in }) + sTwo.takesClosure({ (x: Double, y: Double) in }) } do { @@ -1461,7 +1461,6 @@ let pages3: MutableProperty<(data: DataSourcePage, totalCount: Int)> = Muta // SR-4745 let sr4745 = [1, 2] let _ = sr4745.enumerated().map { (count, element) in "\(count): \(element)" } -// expected-error@-1 {{closure tuple parameter '(offset: Int, element: Int)' does not support destructuring}} {{35-51=(arg) -> <#Result#>}} {{55-55=let (count, element) = arg; return }} // SR-4738 @@ -1472,7 +1471,6 @@ let sr4738 = (1, (2, 3)) // rdar://problem/31892961 let r31892961_1 = [1: 1, 2: 2] r31892961_1.forEach { (k, v) in print(k + v) } -// expected-error@-1 {{closure tuple parameter '(key: Int, value: Int)' does not support destructuring}} {{23-29=(arg)}} {{33-33=let (k, v) = arg; }} let r31892961_2 = [1, 2, 3] let _: [Int] = r31892961_2.enumerated().map { ((index, val)) in @@ -1482,15 +1480,12 @@ let _: [Int] = r31892961_2.enumerated().map { ((index, val)) in } let r31892961_3 = (x: 1, y: 42) -[r31892961_3].map { (x: Int, y: Int) in x + y } -// expected-error@-1 {{closure tuple parameter '(x: Int, y: Int)' does not support destructuring}} {{21-37=(arg: (x: Int, y: Int)) -> <#Result#>}} {{41-41=let (x, y) = arg; return }} +_ = [r31892961_3].map { (x: Int, y: Int) in x + y } -[r31892961_3].map { (x, y: Int) in x + y } -// expected-error@-1 {{closure tuple parameter '(x: Int, y: Int)' does not support destructuring}} {{21-32=(arg: (x: Int, y: Int)) -> <#Result#>}} {{36-36=let (x, y) = arg; return }} +_ = [r31892961_3].map { (x, y: Int) in x + y } let r31892961_4 = (1, 2) -[r31892961_4].map { x, y in x + y } -// expected-error@-1 {{closure tuple parameter '(Int, Int)' does not support destructuring}} {{21-25=(arg) -> <#Result#>}} {{29-29=let (x, y) = arg; return }} +_ = [r31892961_4].map { x, y in x + y } let r31892961_5 = (x: 1, (y: 2, (w: 3, z: 4))) [r31892961_5].map { (x: Int, (y: Int, (w: Int, z: Int))) in x + y } @@ -1526,3 +1521,33 @@ rdar32301091_2 { _ in } // expected-error@-1 {{contextual closure type '(Int, Int) -> ()' expects 2 arguments, but 1 was used in closure body}} {{19-19=,_ }} rdar32301091_2 { x in } // expected-error@-1 {{contextual closure type '(Int, Int) -> ()' expects 2 arguments, but 1 was used in closure body}} {{19-19=,<#arg#> }} + +func rdar32875953() { + let myDictionary = ["hi":1] + + myDictionary.forEach { + print("\($0) -> \($1)") + } + + myDictionary.forEach { key, value in + print("\(key) -> \(value)") + } + + myDictionary.forEach { (key, value) in + print("\(key) -> \(value)") + } + + let array1 = [1] + let array2 = [2] + + _ = zip(array1, array2).map(+) +} + +struct SR_5199 {} +extension Sequence where Iterator.Element == (key: String, value: String?) { + func f() -> [SR_5199] { + return self.map { (key, value) in + SR_5199() // Ok + } + } +} diff --git a/test/Demangle/Inputs/manglings.txt b/test/Demangle/Inputs/manglings.txt index 67bd2ce430f..6a57b44543a 100644 --- a/test/Demangle/Inputs/manglings.txt +++ b/test/Demangle/Inputs/manglings.txt @@ -81,8 +81,12 @@ _TToFC3foo3bar3basfT3zimCS_3zim_T_ ---> {T:_TFC3foo3bar3basfT3zimCS_3zim_T_,C} @ _TTOFSC3fooFTSdSd_Sd ---> {T:_TFSC3fooFTSdSd_Sd} @nonobjc __C.foo(Swift.Double, Swift.Double) -> Swift.Double _T03foo3barC3basyAA3zimCAE_tFTo ---> {T:_T03foo3barC3basyAA3zimCAE_tF,C} @objc foo.bar.bas(zim: foo.zim) -> () _T0SC3fooS2d_SdtFTO ---> {T:_T0SC3fooS2d_SdtF} @nonobjc __C.foo(Swift.Double, Swift.Double) -> Swift.Double -_S3foo3barC3basyAA3zimCAE_tFTo ---> {T:_S3foo3barC3basyAA3zimCAE_tF,C} @objc foo.bar.bas(zim: foo.zim) -> () -_SSC3fooS2d_SdtFTO ---> {T:_SSC3fooS2d_SdtF} @nonobjc __C.foo(Swift.Double, Swift.Double) -> Swift.Double +__$S3foo3barC3basyAA3zimCAE_tFTo ---> {T:_$S3foo3barC3basyAA3zimCAE_tF,C} @objc foo.bar.bas(zim: foo.zim) -> () +__$SSC3fooS2d_SdtFTO ---> {T:_$SSC3fooS2d_SdtF} @nonobjc __C.foo(Swift.Double, Swift.Double) -> Swift.Double +_$S3foo3barC3basyAA3zimCAE_tFTo ---> {T:_$S3foo3barC3basyAA3zimCAE_tF,C} @objc foo.bar.bas(zim: foo.zim) -> () +_$SSC3fooS2d_SdtFTO ---> {T:_$SSC3fooS2d_SdtF} @nonobjc __C.foo(Swift.Double, Swift.Double) -> Swift.Double +$S3foo3barC3basyAA3zimCAE_tFTo ---> {T:$S3foo3barC3basyAA3zimCAE_tF,C} @objc foo.bar.bas(zim: foo.zim) -> () +$SSC3fooS2d_SdtFTO ---> {T:$SSC3fooS2d_SdtF} @nonobjc __C.foo(Swift.Double, Swift.Double) -> Swift.Double _TTDFC3foo3bar3basfT3zimCS_3zim_T_ ---> dynamic foo.bar.bas(zim: foo.zim) -> () _TFC3foo3bar3basfT3zimCS_3zim_T_ ---> foo.bar.bas(zim: foo.zim) -> () _TF3foooi1pFTCS_3barVS_3bas_OS_3zim ---> foo.+ infix(foo.bar, foo.bas) -> foo.zim @@ -260,3 +264,5 @@ _T0A8 ---> _T0A8 _T0s30ReversedRandomAccessCollectionVyxGTfq3nnpf_nTfq1cn_nTfq4x_n ---> _T0s30ReversedRandomAccessCollectionVyxGTfq3nnpf_nTfq1cn_nTfq4x_n _T03abc6testitySiFTm ---> merged abc.testit(Swift.Int) -> () _T04main4TestCACSi1x_tc6_PRIV_Llfc ---> main.Test.(in _PRIV_).init(x: Swift.Int) -> main.Test +_T0SqWy.17 ---> outlined copy of Swift.Optional with unmangled suffix ".17" + diff --git a/test/Driver/Inputs/fake-resource-dir/lib/swift/clang/lib/darwin/libclang_rt.asan_osx_dynamic.dylib b/test/Driver/Inputs/fake-resource-dir/lib/swift/clang/lib/darwin/libclang_rt.asan_osx_dynamic.dylib new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/Driver/Inputs/fake-resource-dir/lib/swift/clang/lib/darwin/libclang_rt.tsan_osx_dynamic.dylib b/test/Driver/Inputs/fake-resource-dir/lib/swift/clang/lib/darwin/libclang_rt.tsan_osx_dynamic.dylib new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/Driver/linker.swift b/test/Driver/linker.swift index 43ae714ec00..b0493e5914b 100644 --- a/test/Driver/linker.swift +++ b/test/Driver/linker.swift @@ -2,6 +2,9 @@ // RUN: %FileCheck %s < %t.simple.txt // RUN: %FileCheck -check-prefix SIMPLE %s < %t.simple.txt +// RUN: %swiftc_driver -driver-print-jobs -target x86_64-apple-macosx10.9 -static-stdlib %s 2>&1 > %t.simple.txt +// RUN: %FileCheck -check-prefix SIMPLE_STATIC -implicit-check-not -rpath %s < %t.simple.txt + // RUN: %swiftc_driver -driver-print-jobs -target x86_64-apple-ios7.1 %s 2>&1 > %t.simple.txt // RUN: %FileCheck -check-prefix IOS_SIMPLE %s < %t.simple.txt @@ -69,6 +72,23 @@ // SIMPLE: -o linker +// SIMPLE_STATIC: swift +// SIMPLE_STATIC: -o [[OBJECTFILE:.*]] + +// SIMPLE_STATIC-NEXT: bin/ld{{"? }} +// SIMPLE_STATIC: [[OBJECTFILE]] +// SIMPLE_STATIC: -lobjc +// SIMPLE_STATIC: -lSystem +// SIMPLE_STATIC: -arch x86_64 +// SIMPLE_STATIC: -L [[STDLIB_PATH:[^ ]+/lib/swift_static/macosx]] +// SIMPLE_STATIC: -lc++ +// SIMPLE_STATIC: -framework Foundation +// SIMPLE_STATIC: -force_load_swift_libs +// SIMPLE_STATIC: -macosx_version_min 10.{{[0-9]+}}.{{[0-9]+}} +// SIMPLE_STATIC: -no_objc_category_merging +// SIMPLE_STATIC: -o linker + + // IOS_SIMPLE: swift // IOS_SIMPLE: -o [[OBJECTFILE:.*]] diff --git a/test/Driver/sanitizers.swift b/test/Driver/sanitizers.swift index ecddad7da1c..9ca56198c18 100644 --- a/test/Driver/sanitizers.swift +++ b/test/Driver/sanitizers.swift @@ -1,25 +1,25 @@ -// RUN: %swiftc_driver -driver-print-jobs -sanitize=address -target x86_64-apple-macosx10.9 %s | %FileCheck -check-prefix=ASAN -check-prefix=ASAN_OSX %s -// RUN: %swiftc_driver -driver-print-jobs -sanitize=address -target x86_64-apple-ios7.1 %s | %FileCheck -check-prefix=ASAN -check-prefix=ASAN_IOSSIM %s -// RUN: %swiftc_driver -driver-print-jobs -sanitize=address -target arm64-apple-ios7.1 %s | %FileCheck -check-prefix=ASAN -check-prefix=ASAN_IOS %s -// RUN: %swiftc_driver -driver-print-jobs -sanitize=address -target x86_64-apple-tvos9.0 %s | %FileCheck -check-prefix=ASAN -check-prefix=ASAN_tvOS_SIM %s -// RUN: %swiftc_driver -driver-print-jobs -sanitize=address -target arm64-apple-tvos9.0 %s | %FileCheck -check-prefix=ASAN -check-prefix=ASAN_tvOS %s -// RUN: %swiftc_driver -driver-print-jobs -sanitize=address -target i386-apple-watchos2.0 %s | %FileCheck -check-prefix=ASAN -check-prefix=ASAN_watchOS_SIM %s -// RUN: %swiftc_driver -driver-print-jobs -sanitize=address -target armv7k-apple-watchos2.0 %s | %FileCheck -check-prefix=ASAN -check-prefix=ASAN_watchOS %s -// RUN: not %swiftc_driver -driver-print-jobs -sanitize=address -target x86_64-unknown-linux-gnu %s 2>&1 | %FileCheck -check-prefix=ASAN_LINUX %s +// RUN: %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=address -target x86_64-apple-macosx10.9 %s | %FileCheck -check-prefix=ASAN -check-prefix=ASAN_OSX %s +// RUN: %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=address -target x86_64-apple-ios7.1 %s | %FileCheck -check-prefix=ASAN -check-prefix=ASAN_IOSSIM %s +// RUN: %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=address -target arm64-apple-ios7.1 %s | %FileCheck -check-prefix=ASAN -check-prefix=ASAN_IOS %s +// RUN: %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=address -target x86_64-apple-tvos9.0 %s | %FileCheck -check-prefix=ASAN -check-prefix=ASAN_tvOS_SIM %s +// RUN: %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=address -target arm64-apple-tvos9.0 %s | %FileCheck -check-prefix=ASAN -check-prefix=ASAN_tvOS %s +// RUN: %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=address -target i386-apple-watchos2.0 %s | %FileCheck -check-prefix=ASAN -check-prefix=ASAN_watchOS_SIM %s +// RUN: %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=address -target armv7k-apple-watchos2.0 %s | %FileCheck -check-prefix=ASAN -check-prefix=ASAN_watchOS %s +// RUN: not %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=address -target x86_64-unknown-linux-gnu %s 2>&1 | %FileCheck -check-prefix=ASAN_LINUX %s -// RUN: %swiftc_driver -driver-print-jobs -sanitize=thread -target x86_64-apple-macosx10.9 %s | %FileCheck -check-prefix=TSAN -check-prefix=TSAN_OSX %s -// RUN: not %swiftc_driver -driver-print-jobs -sanitize=thread -target x86-apple-macosx10.9 %s 2>&1 | %FileCheck -check-prefix=TSAN_OSX_32 %s -// RUN: %swiftc_driver -driver-print-jobs -sanitize=thread -target x86_64-apple-ios7.1 %s | %FileCheck -check-prefix=TSAN -check-prefix=TSAN_IOSSIM %s -// RUN: not %swiftc_driver -driver-print-jobs -sanitize=thread -target arm64-apple-ios7.1 %s 2>&1 | %FileCheck -check-prefix=TSAN_IOS %s -// RUN: %swiftc_driver -driver-print-jobs -sanitize=thread -target x86_64-apple-tvos9.0 %s | %FileCheck -check-prefix=TSAN -check-prefix=TSAN_tvOS_SIM %s -// RUN: not %swiftc_driver -driver-print-jobs -sanitize=thread -target arm64-apple-tvos9.0 %s 2>&1 | %FileCheck -check-prefix=TSAN_tvOS %s -// RUN: not %swiftc_driver -driver-print-jobs -sanitize=thread -target i386-apple-watchos2.0 %s 2>&1 | %FileCheck -check-prefix=TSAN_watchOS_SIM %s -// RUN: not %swiftc_driver -driver-print-jobs -sanitize=thread -target armv7k-apple-watchos2.0 %s 2>&1 | %FileCheck -check-prefix=TSAN_watchOS %s -// RUN: not %swiftc_driver -driver-print-jobs -sanitize=thread -target x86_64-unknown-linux-gnu %s 2>&1 | %FileCheck -check-prefix=TSAN_LINUX %s +// RUN: %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=thread -target x86_64-apple-macosx10.9 %s | %FileCheck -check-prefix=TSAN -check-prefix=TSAN_OSX %s +// RUN: not %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=thread -target x86-apple-macosx10.9 %s 2>&1 | %FileCheck -check-prefix=TSAN_OSX_32 %s +// RUN: not %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=thread -target x86_64-apple-ios7.1 %s 2>&1 | %FileCheck -check-prefix=TSAN_IOSSIM %s +// RUN: not %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=thread -target arm64-apple-ios7.1 %s 2>&1 | %FileCheck -check-prefix=TSAN_IOS %s +// RUN: not %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=thread -target x86_64-apple-tvos9.0 %s 2>&1 | %FileCheck -check-prefix=TSAN_tvOS_SIM %s +// RUN: not %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=thread -target arm64-apple-tvos9.0 %s 2>&1 | %FileCheck -check-prefix=TSAN_tvOS %s +// RUN: not %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=thread -target i386-apple-watchos2.0 %s 2>&1 | %FileCheck -check-prefix=TSAN_watchOS_SIM %s +// RUN: not %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=thread -target armv7k-apple-watchos2.0 %s 2>&1 | %FileCheck -check-prefix=TSAN_watchOS %s +// RUN: not %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=thread -target x86_64-unknown-linux-gnu %s 2>&1 | %FileCheck -check-prefix=TSAN_LINUX %s -// RUN: not %swiftc_driver -driver-print-jobs -sanitize=address,unknown %s 2>&1 | %FileCheck -check-prefix=BADARG %s -// RUN: not %swiftc_driver -driver-print-jobs -sanitize=address -sanitize=unknown %s 2>&1 | %FileCheck -check-prefix=BADARG %s -// RUN: not %swiftc_driver -driver-print-jobs -sanitize=address,thread %s 2>&1 | %FileCheck -check-prefix=INCOMPATIBLESANITIZERS %s +// RUN: not %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=address,unknown %s 2>&1 | %FileCheck -check-prefix=BADARG %s +// RUN: not %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=address -sanitize=unknown %s 2>&1 | %FileCheck -check-prefix=BADARG %s +// RUN: not %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=address,thread %s 2>&1 | %FileCheck -check-prefix=INCOMPATIBLESANITIZERS %s // ASAN: swift // ASAN: -sanitize=address @@ -40,9 +40,9 @@ // TSAN_OSX: lib/swift/clang/lib/darwin/libclang_rt.tsan_osx_dynamic.dylib // TSAN_OSX_32: unsupported option '-sanitize=thread' for target 'x86-apple-macosx10.9' -// TSAN_IOSSIM: lib/swift/clang/lib/darwin/libclang_rt.tsan_iossim_dynamic.dylib +// TSAN_IOSSIM: unsupported option '-sanitize=thread' for target 'x86_64-apple-ios7.1' // TSAN_IOS: unsupported option '-sanitize=thread' for target 'arm64-apple-ios7.1' -// TSAN_tvOS_SIM: lib/swift/clang/lib/darwin/libclang_rt.tsan_tvossim_dynamic.dylib +// TSAN_tvOS_SIM: unsupported option '-sanitize=thread' for target 'x86_64-apple-tvos9.0' // TSAN_tvOS: unsupported option '-sanitize=thread' for target 'arm64-apple-tvos9.0' // TSAN_watchOS_SIM: unsupported option '-sanitize=thread' for target 'i386-apple-watchos2.0' // TSAN_watchOS: unsupported option '-sanitize=thread' for target 'armv7k-apple-watchos2.0' diff --git a/test/FixCode/fixits-switch.swift.result b/test/FixCode/fixits-switch.swift.result index 03a422562c1..49ab57d4c14 100644 --- a/test/FixCode/fixits-switch.swift.result +++ b/test/FixCode/fixits-switch.swift.result @@ -55,19 +55,19 @@ func foo4(_ e : E2) -> Int { switch e { case .e2: return 1 - case .e1(_, _): + case .e1(let a, let s): <#code#> -case .e3(_): +case .e3(let a): <#code#> case .e4(_): <#code#> case .e5(_, _): <#code#> -case .e6(_, _): +case .e6(let a, _): <#code#> case .e7: <#code#> -case .e8(_, _, _): +case .e8(let a, _, _): <#code#> case .e9(_, _, _): <#code#> @@ -93,19 +93,19 @@ func foo6(_ e : E2) -> Int { switch e { case let .e1(x, y): return x + y - case .e2(_): + case .e2(let a): <#code#> -case .e3(_): +case .e3(let a): <#code#> case .e4(_): <#code#> case .e5(_, _): <#code#> -case .e6(_, _): +case .e6(let a, _): <#code#> case .e7: <#code#> -case .e8(_, _, _): +case .e8(let a, _, _): <#code#> case .e9(_, _, _): <#code#> @@ -117,17 +117,17 @@ func foo7(_ e : E2) -> Int { case .e2(1): return 0 case .e1: return 0 case .e3: return 0 - case .e2(_): + case .e2(let a): <#code#> case .e4(_): <#code#> case .e5(_, _): <#code#> -case .e6(_, _): +case .e6(let a, _): <#code#> case .e7: <#code#> -case .e8(_, _, _): +case .e8(let a, _, _): <#code#> case .e9(_, _, _): <#code#> diff --git a/test/Frontend/embed-bitcode-tvos.ll b/test/Frontend/embed-bitcode-tvos.ll new file mode 100644 index 00000000000..ccac4431576 --- /dev/null +++ b/test/Frontend/embed-bitcode-tvos.ll @@ -0,0 +1,20 @@ +; REQUIRES: CODEGENERATOR=AArch64 +; RUN: llvm-as %s -o %t.bc +; RUN: %swift -target arm64-apple-tvos9 -c -module-name someModule -embed-bitcode -disable-llvm-optzns -o %t2.o %t.bc -dump-clang-diagnostics 2> %t.diags.txt +; RUN: llvm-objdump -macho -private-headers %t2.o | %FileCheck %s +; RUN: %FileCheck -check-prefix CHECK-IMPORTER %s < %t.diags.txt + +target triple = "arm64-apple-tvos9.0" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" + +; CHECK: LC_VERSION_MIN_TVOS + +; CHECK-IMPORTER: clang +; CHECK-IMPORTER: -fembed-bitcode +; CHECK-IMPORTER: -target +; CHECK-IMPORTER: -mtvos-version-min=9 +; CHECK-IMPORTER-NOT: argument unused + +define i32 @f0() nounwind ssp { + ret i32 0 +} diff --git a/test/Frontend/embed-bitcode.ll b/test/Frontend/embed-bitcode.ll index c6f7a377a87..eda62adb6d4 100644 --- a/test/Frontend/embed-bitcode.ll +++ b/test/Frontend/embed-bitcode.ll @@ -23,6 +23,7 @@ target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" ; CHECK-IMPORTER: clang ; CHECK-IMPORTER: -fembed-bitcode ; CHECK-IMPORTER: -target +; CHECK-IMPORTER-NOT: argument unused define i32 @f0() nounwind ssp { ret i32 0 diff --git a/test/Frontend/unknown-arguments.swift b/test/Frontend/unknown-arguments.swift index 0e681b26d8e..e8f8553771e 100644 --- a/test/Frontend/unknown-arguments.swift +++ b/test/Frontend/unknown-arguments.swift @@ -9,6 +9,6 @@ // RUN: not %swiftc_driver -D Correct -DAlsoCorrect -D@#%! -D Swift=Cool -D-D -c %s -o %t.o 2>&1 | %FileCheck -check-prefix=INVALID-COND %s // INVALID-COND: :0: error: conditional compilation flags must be valid Swift identifiers (rather than '@#%!') -// INVALID-COND-NEXT: :0: error: conditional compilation flags do not have values in Swift; they are either present or absent (rather than 'Swift=Cool') +// INVALID-COND-NEXT: :0: warning: conditional compilation flags do not have values in Swift; they are either present or absent (rather than 'Swift=Cool') // INVALID-COND-NEXT: :0: error: conditional compilation flags must be valid Swift identifiers (rather than '-D') diff --git a/test/Generics/associated_type_typo.swift b/test/Generics/associated_type_typo.swift index 24d5f81ade2..8a5dc06c9c4 100644 --- a/test/Generics/associated_type_typo.swift +++ b/test/Generics/associated_type_typo.swift @@ -30,9 +30,9 @@ func typoAssoc3(t: T, u: U) where U.AssocP2.assoc : P3, T.AssocP2.assoc : P4, T.AssocP2 == U.AssocP2 {} -// expected-error@+3{{'T.AssocP2' does not have a member type named 'assoc'; did you mean 'Assoc'?}}{{47-52=Assoc}} +// expected-error@+3{{'T.AssocP2' does not have a member type named 'assoc'; did you mean 'Assoc'?}} // expected-error@+2{{'T' does not have a member type named 'Assocp2'; did you mean 'AssocP2'?}}{{39-46=AssocP2}} -// expected-error@+1{{'T.AssocP2' does not have a member type named 'assoc'; did you mean 'Assoc'?}} +// expected-error@+1{{'assoc' is not a member type of 'T.AssocP2'}} func typoAssoc4(_: T) where T.Assocp2.assoc : P3 {} diff --git a/test/Generics/deduction.swift b/test/Generics/deduction.swift index 0a6735348d9..02408edf789 100644 --- a/test/Generics/deduction.swift +++ b/test/Generics/deduction.swift @@ -22,7 +22,7 @@ func useIdentity(_ x: Int, y: Float, i32: Int32) { // Deduction where the result type and input type can get different results var xx : X, yy : Y - xx = identity(yy) // expected-error{{cannot convert value of type 'Y' to expected argument type 'X'}} + xx = identity(yy) // expected-error{{cannot assign value of type 'Y' to type 'X'}} xx = identity2(yy) // expected-error{{cannot convert value of type 'Y' to expected argument type 'X'}} } diff --git a/test/Generics/invalid.swift b/test/Generics/invalid.swift index b6e95006786..60b320c6bc8 100644 --- a/test/Generics/invalid.swift +++ b/test/Generics/invalid.swift @@ -54,8 +54,8 @@ func eatDinnerConcrete(d: Pizzas.DeepDish, func badDiagnostic1() { _ = Lunch.NewYork>.Dinner( - leftovers: Pizzas.NewYork(), - transformation: { _ in HotDog() }) // expected-error {{cannot convert value of type 'HotDog' to closure result type '_'}} + leftovers: Pizzas.NewYork(), // expected-error {{cannot convert value of type 'Pizzas.NewYork' to expected argument type 'Pizzas.NewYork'}} + transformation: { _ in HotDog() }) } func badDiagnostic2() { diff --git a/test/Generics/protocol_type_aliases.swift b/test/Generics/protocol_type_aliases.swift index cf0cfbd168c..46263493145 100644 --- a/test/Generics/protocol_type_aliases.swift +++ b/test/Generics/protocol_type_aliases.swift @@ -53,21 +53,17 @@ func concreteRequirementOnConcreteNestedTypeAlias(_: T) where T: Q2, S = // Incompatible concrete typealias types are flagged as such protocol P3 { - typealias T = Int // expected-error{{type alias 'T' requires types 'Q3.T' (aka 'Float') and 'Int' to be the same}} + typealias T = Int } -protocol Q3: P3 { +protocol Q3: P3 { // expected-error{{generic signature requires types 'Int'}} typealias T = Float } protocol P3_1 { - typealias T = Float // expected-error{{type alias 'T' requires types 'P3.T' (aka 'Int') and 'Float' to be the same}} + typealias T = Float } protocol Q3_1: P3, P3_1 {} // expected-error{{generic signature requires types 'Float'}} -// FIXME: these shouldn't be necessary to trigger the errors above, but are, due to -// the 'recursive decl validation' FIXME in GenericSignatureBuilder.cpp. -func useTypealias(_: T, _: T.T) {} -func useTypealias1(_: T, _: T.T) {} // Subprotocols can force associated types in their parents to be concrete, and // this should be understood for types constrained by the subprotocols. @@ -114,3 +110,11 @@ func checkQ6(x: T.Type) { sameType(getP6_1_A(x), getP6_2_B(x)) } +protocol P7 { + typealias A = Int +} + +protocol P7a : P7 { + associatedtype A // expected-warning{{associated type 'A' is redundant with type 'A' declared in inherited protocol 'P7'}} +} + diff --git a/test/Generics/requirement_inference.swift b/test/Generics/requirement_inference.swift index 45904ce1df0..df14ea8716d 100644 --- a/test/Generics/requirement_inference.swift +++ b/test/Generics/requirement_inference.swift @@ -224,8 +224,8 @@ struct X8 : P12 { struct X9 where T.B == U.B { // CHECK-LABEL: X9.upperSameTypeConstraint - // CHECK: Generic signature: - // CHECK: Canonical generic signature: <τ_0_0, τ_0_1, τ_1_0 where τ_0_1 : P12, τ_0_0 == X8, τ_0_1.B == X7> + // CHECK: Generic signature: + // CHECK: Canonical generic signature: <τ_0_0, τ_0_1, τ_1_0 where τ_0_0 == X8, τ_0_1 : P12, τ_0_1.B == X7> func upperSameTypeConstraint(_: V) where T == X8 { } } diff --git a/test/Generics/same_type_constraints.swift b/test/Generics/same_type_constraints.swift index f529fd6edc8..01b3294525d 100644 --- a/test/Generics/same_type_constraints.swift +++ b/test/Generics/same_type_constraints.swift @@ -352,11 +352,11 @@ func intercomponentSameComponents(_: T) // FIXME: directionality of constraint above is weird func intercomponentMoreThanSpanningTree(_: T) - where T.A == T.B, // expected-note{{previous same-type constraint 'T.A' == 'T.B' written here}} + where T.A == T.B, T.B == T.C, - T.D == T.E, // expected-warning{{redundant same-type constraint 'T.D' == 'T.E'}} + T.D == T.E, // expected-note{{previous same-type constraint 'T.D' == 'T.E' written here}} T.D == T.B, - T.E == T.B + T.E == T.B // expected-warning{{redundant same-type constraint 'T.B' == 'T.E'}} { } func trivialRedundancy(_: T) where T.A == T.A { } // expected-warning{{redundant same-type constraint 'T.A' == 'T.A'}} @@ -365,3 +365,10 @@ struct X11 where T.A == T.B { } func intracomponentInferred(_: X11) // expected-note{{previous same-type constraint 'T.A' == 'T.B' inferred from type here}} where T.A == T.B { } // expected-warning{{redundant same-type constraint 'T.A' == 'T.B'}} + +// Suppress redundant same-type constraint warnings from result types. +struct StructTakingP1 { } + +func resultTypeSuppress() -> StructTakingP1 { + return StructTakingP1() +} diff --git a/test/Generics/superclass_constraint.swift b/test/Generics/superclass_constraint.swift index 94a37e081ed..16ed23b689a 100644 --- a/test/Generics/superclass_constraint.swift +++ b/test/Generics/superclass_constraint.swift @@ -76,7 +76,7 @@ extension P2 where Self.T : C { // CHECK: superclassConformance1 // CHECK: Requirements: // CHECK-NEXT: τ_0_0 : C [τ_0_0: Explicit @ {{.*}}:11] -// CHECK-NEXT: τ_0_0 : _NativeClass [τ_0_0: Explicit @ {{.*}}:11 -> Superclass] +// CHECK-NEXT: τ_0_0 : _NativeClass [τ_0_0: Explicit @ {{.*}}:11 -> Derived] // CHECK-NEXT: τ_0_0 : P3 [τ_0_0: Explicit @ {{.*}}:11 -> Superclass (C: P3)] // CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C> func superclassConformance1(t: T) @@ -88,7 +88,7 @@ func superclassConformance1(t: T) // CHECK: superclassConformance2 // CHECK: Requirements: // CHECK-NEXT: τ_0_0 : C [τ_0_0: Explicit @ {{.*}}:11] -// CHECK-NEXT: τ_0_0 : _NativeClass [τ_0_0: Explicit @ {{.*}}:11 -> Superclass] +// CHECK-NEXT: τ_0_0 : _NativeClass [τ_0_0: Explicit @ {{.*}}:11 -> Derived] // CHECK-NEXT: τ_0_0 : P3 [τ_0_0: Explicit @ {{.*}}:11 -> Superclass (C: P3)] // CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C> func superclassConformance2(t: T) @@ -102,7 +102,7 @@ class C2 : C, P4 { } // CHECK: superclassConformance3 // CHECK: Requirements: // CHECK-NEXT: τ_0_0 : C2 [τ_0_0: Explicit @ {{.*}}:61] -// CHECK-NEXT: τ_0_0 : _NativeClass [τ_0_0: Explicit @ {{.*}}:46 -> Superclass] +// CHECK-NEXT: τ_0_0 : _NativeClass [τ_0_0: Explicit @ {{.*}}:46 -> Derived] // CHECK-NEXT: τ_0_0 : P4 [τ_0_0: Explicit @ {{.*}}:61 -> Superclass (C2: P4)] // CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : C2> func superclassConformance3(t: T) where T : C, T : P4, T : C2 {} diff --git a/test/IDE/Inputs/custom-modules/Newtype.h b/test/IDE/Inputs/custom-modules/Newtype.h index 3fb29a927bd..476dbeab2f1 100644 --- a/test/IDE/Inputs/custom-modules/Newtype.h +++ b/test/IDE/Inputs/custom-modules/Newtype.h @@ -102,3 +102,29 @@ __attribute((swift_name("NSSomeContext.Name"))); extern const NSSomeContextName NSMyContextName; +typedef struct T *TRef __attribute((swift_newtype(struct))); +typedef const struct T *ConstTRef __attribute((swift_newtype(struct))); +extern _Nonnull TRef create_T(void); +extern _Nonnull ConstTRef create_ConstT(void); +extern void destroy_T(TRef); +extern void destroy_ConstT(ConstTRef); + +extern void mutate_TRef_Pointee(TRef) __attribute((swift_name("TRef.mutatePointee(self:)"))); +extern void mutate_TRef(TRef *) __attribute((swift_name("TRef.mutate(self:)"))); +extern void use_ConstT(ConstTRef) + __attribute((swift_name("ConstTRef.use(self:)"))); + + +typedef struct T *__nonnull *TRefRef __attribute((swift_newtype(struct))); +typedef struct T *__nonnull const *ConstTRefRef __attribute((swift_newtype(struct))); +extern _Nonnull TRefRef create_TRef(void); +extern _Nonnull ConstTRefRef create_ConstTRef(void); +extern void destroy_TRef(TRefRef); +extern void destroy_ConstTRef(ConstTRefRef); + +extern void mutate_TRefRef_Pointee(TRefRef) + __attribute((swift_name("TRefRef.mutatePointee(self:)"))); +extern void mutate_TRefRef(TRefRef*) + __attribute((swift_name("TRefRef.mutate(self:)"))); +extern void use_ConstTRef(ConstTRefRef) + __attribute((swift_name("ConstTRefRef.use(self:)"))); diff --git a/test/IDE/coloring_unclosed_hash_if.swift b/test/IDE/coloring_unclosed_hash_if.swift new file mode 100644 index 00000000000..a680085fb69 --- /dev/null +++ b/test/IDE/coloring_unclosed_hash_if.swift @@ -0,0 +1,14 @@ +// RUN: %target-swift-ide-test -syntax-coloring -source-filename %s | %FileCheck %s +// RUN: %target-swift-ide-test -syntax-coloring -typecheck -source-filename %s | %FileCheck %s + +// CHECK: <#kw>#if <#id>d +// CHECK-NEXT: func bar() { +// CHECK-NEXT: <#kw>#if <#id>d +// CHECK-NEXT: } +// CHECK-NEXT: func foo() {} + +#if d +func bar() { + #if d +} +func foo() {} diff --git a/test/IDE/complete_override.swift b/test/IDE/complete_override.swift index 147331c8eac..a9be1e73cd3 100644 --- a/test/IDE/complete_override.swift +++ b/test/IDE/complete_override.swift @@ -135,6 +135,9 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=PROTOINIT_FINAL -code-completion-keywords=false | %FileCheck %s -check-prefix=PROTOINIT_FINAL // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=PROTOINIT_STRUCT -code-completion-keywords=false | %FileCheck %s -check-prefix=PROTOINIT_STRUCT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=MISSING_ASSOC_1 -code-completion-keywords=false | %FileCheck %s -check-prefix=MISSING_ASSOC_1 + + @objc class TagPA {} @objc @@ -704,3 +707,22 @@ struct RequiredS : RequiredP { // PROTOINIT_STRUCT: Begin completions, 1 items // PROTOINIT_STRUCT-DAG: init(p: Int) {|}; name=init(p: Int) // PROTOINIT_STRUCT: End completions + +protocol AssocAndMethod { + associatedtype T = Int + associatedtype U: P0 + associatedtype V + + func f1(_: T) + func f2(_: U) + func f3(_: V) +} + +struct MissingAssoc: AssocAndMethod { + func #^MISSING_ASSOC_1^# +} +// MISSING_ASSOC_1: Begin completions +// MISSING_ASSOC_1-DAG: Decl[InstanceMethod]/Super: f1(_: MissingAssoc.T) {|}; +// MISSING_ASSOC_1-DAG: Decl[InstanceMethod]/Super: f2(_: MissingAssoc.U) {|}; +// MISSING_ASSOC_1-DAG: Decl[InstanceMethod]/Super: f3(_: MissingAssoc.V) {|}; +// MISSING_ASSOC_1: End completions diff --git a/test/IDE/newtype.swift b/test/IDE/newtype.swift index e3f6402ee23..bd697cdfee9 100644 --- a/test/IDE/newtype.swift +++ b/test/IDE/newtype.swift @@ -149,6 +149,54 @@ // PRINT-NEXT: extension NSSomeContext.Name { // PRINT-NEXT: static let myContextName: NSSomeContext.Name // PRINT-NEXT: } +// +// PRINT-NEXT: struct TRef : RawRepresentable, _SwiftNewtypeWrapper, Equatable, Hashable { +// PRINT-NEXT: init(_ rawValue: OpaquePointer) +// PRINT-NEXT: init(rawValue: OpaquePointer) +// PRINT-NEXT: let rawValue: OpaquePointer +// PRINT-NEXT: typealias RawValue = OpaquePointer +// PRINT-NEXT: } +// PRINT-NEXT: struct ConstTRef : RawRepresentable, _SwiftNewtypeWrapper, Equatable, Hashable { +// PRINT-NEXT: init(_ rawValue: OpaquePointer) +// PRINT-NEXT: init(rawValue: OpaquePointer) +// PRINT-NEXT: let rawValue: OpaquePointer +// PRINT-NEXT: typealias RawValue = OpaquePointer +// PRINT-NEXT: } +// PRINT-NEXT: func create_T() -> TRef +// PRINT-NEXT: func create_ConstT() -> ConstTRef +// PRINT-NEXT: func destroy_T(_: TRef!) +// PRINT-NEXT: func destroy_ConstT(_: ConstTRef!) +// PRINT-NEXT: extension TRef { +// PRINT-NEXT: func mutatePointee() +// PRINT-NEXT: mutating func mutate() +// PRINT-NEXT: } +// PRINT-NEXT: extension ConstTRef { +// PRINT-NEXT: func use() +// PRINT-NEXT: } +// +// PRINT-NEXT: struct TRefRef : RawRepresentable, _SwiftNewtypeWrapper, Equatable, Hashable { +// PRINT-NEXT: init(_ rawValue: UnsafeMutablePointer) +// PRINT-NEXT: init(rawValue: UnsafeMutablePointer) +// PRINT-NEXT: let rawValue: UnsafeMutablePointer +// PRINT-NEXT: typealias RawValue = UnsafeMutablePointer +// PRINT-NEXT: } +// PRINT-NEXT: struct ConstTRefRef : RawRepresentable, _SwiftNewtypeWrapper, Equatable, Hashable { +// PRINT-NEXT: init(_ rawValue: UnsafePointer) +// PRINT-NEXT: init(rawValue: UnsafePointer) +// PRINT-NEXT: let rawValue: UnsafePointer +// PRINT-NEXT: typealias RawValue = UnsafePointer +// PRINT-NEXT: } +// PRINT-NEXT: func create_TRef() -> TRefRef +// PRINT-NEXT: func create_ConstTRef() -> ConstTRefRef +// PRINT-NEXT: func destroy_TRef(_: TRefRef!) +// PRINT-NEXT: func destroy_ConstTRef(_: ConstTRefRef!) +// PRINT-NEXT: extension TRefRef { +// PRINT-NEXT: func mutatePointee() +// PRINT-NEXT: mutating func mutate() +// PRINT-NEXT: } +// PRINT-NEXT: extension ConstTRefRef { +// PRINT-NEXT: func use() +// PRINT-NEXT: } import Newtype diff --git a/test/IDE/print_ast_non_typechecked.swift b/test/IDE/print_ast_non_typechecked.swift index 90b2d463059..dfc4c56522f 100644 --- a/test/IDE/print_ast_non_typechecked.swift +++ b/test/IDE/print_ast_non_typechecked.swift @@ -4,3 +4,24 @@ class C { // RUN: %target-swift-ide-test -print-ast-not-typechecked -source-filename %s | %FileCheck %s -check-prefix=CHECK1 // CHECK1: func foo(s: Int) + +#if BAR +func bar() {} +#elseif BAZ +func baz() {} +#else +func qux() {} +#endif + +// CHECK1: {{^}}#if /* condition */ +// CHECK1: {{^}} func bar() { +// CHECK1: {{^}} } +// CHECK1: {{^}}#elseif /* condition */ +// CHECK1: {{^}} func baz() { +// CHECK1: {{^}} } +// CHECK1: {{^}}#else +// CHECK1: {{^}} func qux() { +// CHECK1: {{^}} } +// CHECK1: {{^}}#endif +// CHECK1: {{^}}func qux() { +// CHECK1: {{^}}} diff --git a/test/IDE/print_clang_decls.swift b/test/IDE/print_clang_decls.swift index 98f8418002b..ad14dcb3f86 100644 --- a/test/IDE/print_clang_decls.swift +++ b/test/IDE/print_clang_decls.swift @@ -122,6 +122,17 @@ // FOUNDATION-NEXT: @available(*, unavailable, message: "Zone-based memory management is unavailable") // FOUNDATION-NEXT: NSSetZoneName(_ zone: NSZone, _ name: String) +// FOUNDATION-LABEL: struct FictionalServerError +// FOUNDATION: enum Code +// FOUNDATION: case meltedDown +// FOUNDATION: static var meltedDown: FictionalServerError.Code + +// FOUNDATION-LABEL: extension NSLaundromat { +// FOUNDATION-NEXT: struct Error +// FOUNDATION: enum Code +// FOUNDATION: case tooMuchSoap +// FOUNDATION: static var tooMuchSoap: NSLaundromat.Error.Code { get } + // CTYPESBITS-NOT: FooStruct1 // CTYPESBITS: {{^}}typealias DWORD = Int32{{$}} // CTYPESBITS-NEXT: {{^}}var MY_INT: Int32 { get }{{$}} diff --git a/test/IDE/print_source_file_interface_1.swift.result b/test/IDE/print_source_file_interface_1.swift.result index f1f48735252..fbf08d5f43c 100644 --- a/test/IDE/print_source_file_interface_1.swift.result +++ b/test/IDE/print_source_file_interface_1.swift.result @@ -3,8 +3,6 @@ // More blah blah. - - import Swift internal class FooDisabled { diff --git a/test/IRGen/Inputs/conformance_multifile_1.swift b/test/IRGen/Inputs/conformance_multifile_1.swift new file mode 100644 index 00000000000..70cb8281a22 --- /dev/null +++ b/test/IRGen/Inputs/conformance_multifile_1.swift @@ -0,0 +1,10 @@ +protocol Super {} +protocol P : Super { } + +enum E {} + +extension E : P { } + +enum E2 { + case Filter(P) +} diff --git a/test/IRGen/access_markers.sil b/test/IRGen/access_markers.sil index ad26ee9e666..068e44df1ec 100644 --- a/test/IRGen/access_markers.sil +++ b/test/IRGen/access_markers.sil @@ -114,8 +114,7 @@ sil @testPairedBox : $(@guaranteed { var () }) -> () { bb0(%0 : ${ var () }): // CHECK: entry: %2 = project_box %0 : ${ var () }, 0 - - // CHECK-NEXT: call {{.*}}void @writeEmptyTuple(%swift.opaque* nocapture undef) + // CHECK-NEXT: call {{.*}}void @writeEmptyTuple(%swift.opaque* nocapture undef) %3 = begin_access [modify] [dynamic] %2 : $*() %write_fn = function_ref @writeEmptyTuple : $@convention(thin) (@inout ()) -> () apply %write_fn(%3) : $@convention(thin) (@inout ()) -> () diff --git a/test/IRGen/big_types_corner_cases.swift b/test/IRGen/big_types_corner_cases.swift index 9ae7eb33f6f..f416a540b4a 100644 --- a/test/IRGen/big_types_corner_cases.swift +++ b/test/IRGen/big_types_corner_cases.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -enable-large-loadable-types %s -emit-ir | %FileCheck %s +// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -enable-large-loadable-types %s -emit-ir | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize public struct BigStruct { var i0 : Int32 = 0 @@ -83,7 +83,7 @@ public class BigClass { } } -// CHECK-LABEL define{{( protected)?}} hidden swiftcc void @_T022big_types_corner_cases8BigClassC03useE6StructyAA0eH0V0aH0_tF(%T22big_types_corner_cases9BigStructV* noalias nocapture dereferenceable({{.*}}), %T22big_types_corner_cases8BigClassC* swiftself) #0 { +// CHECK-LABEL: define{{( protected)?}} hidden swiftcc void @_T022big_types_corner_cases8BigClassC03useE6StructyAA0eH0V0aH0_tF(%T22big_types_corner_cases9BigStructV* noalias nocapture dereferenceable({{.*}}), %T22big_types_corner_cases8BigClassC* swiftself) #0 { // CHECK: getelementptr inbounds %T22big_types_corner_cases8BigClassC, %T22big_types_corner_cases8BigClassC* // CHECK: call void @_T0SqWy // CHECK: [[BITCAST:%.*]] = bitcast i8* {{.*}} to void (%T22big_types_corner_cases9BigStructV*, %swift.refcounted*)* @@ -111,3 +111,28 @@ class Foo { // CHECK: getelementptr inbounds void (i8*, %swift.refcounted*, %T22big_types_corner_cases3FooC*)*, void (i8*, %swift.refcounted*, %T22big_types_corner_cases3FooC*)** // CHECK: call noalias %swift.refcounted* @swift_rt_swift_allocObject(%swift.type* getelementptr inbounds (%swift.full_boxmetadata, %swift.full_boxmetadata* // CHECK: ret { i8*, %swift.refcounted* } + +public enum LargeEnum { + public enum InnerEnum { + case simple(Int64) + case hard(Int64, String?) + } + case Empty1 + case Empty2 + case Full(InnerEnum) +} + +public func enumCallee(_ x: LargeEnum) { + switch x { + case .Full(let inner): print(inner) + case .Empty1: break + case .Empty2: break + } +} +// CHECK-LABEL-64: define{{( protected)?}} swiftcc void @_T022big_types_corner_cases10enumCalleeyAA9LargeEnumOF(%T22big_types_corner_cases9LargeEnumO* noalias nocapture dereferenceable(34)) #0 { +// CHECK-64: alloca %T22big_types_corner_cases9LargeEnumO05InnerF0O +// CHECK-64: alloca %T22big_types_corner_cases9LargeEnumO +// CHECK-64: call void @llvm.memcpy.p0i8.p0i8.i64 +// CHECK-64: call void @llvm.memcpy.p0i8.p0i8.i64 +// CHECK-64: call %swift.type* @_T0ypMa() +// CHECK-64: ret void diff --git a/test/IRGen/builtins.swift b/test/IRGen/builtins.swift index 6786f2fa386..5e450cff289 100644 --- a/test/IRGen/builtins.swift +++ b/test/IRGen/builtins.swift @@ -531,7 +531,7 @@ struct Abc { var value : Builtin.Word } -// CHECK-LABEL define hidden {{.*}}@_T08builtins22assumeNonNegative_testBwAA3AbcVzF +// CHECK-LABEL: define hidden {{.*}}@_T08builtins22assumeNonNegative_testBwAA3AbcVzF func assumeNonNegative_test(_ x: inout Abc) -> Builtin.Word { // CHECK: load {{.*}}, !range ![[R:[0-9]+]] return Builtin.assumeNonNegative_Word(x.value) @@ -542,7 +542,7 @@ func return_word(_ x: Builtin.Word) -> Builtin.Word { return x } -// CHECK-LABEL define hidden {{.*}}@_T08builtins23assumeNonNegative_test2BwAA3AbcVzF +// CHECK-LABEL: define hidden {{.*}}@_T08builtins23assumeNonNegative_test2BwBwF func assumeNonNegative_test2(_ x: Builtin.Word) -> Builtin.Word { // CHECK: call {{.*}}, !range ![[R]] return Builtin.assumeNonNegative_Word(return_word(x)) diff --git a/test/IRGen/conformance_multifile.swift b/test/IRGen/conformance_multifile.swift new file mode 100644 index 00000000000..961763cbd05 --- /dev/null +++ b/test/IRGen/conformance_multifile.swift @@ -0,0 +1,8 @@ +// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-ir -primary-file %s %S/Inputs/conformance_multifile_1.swift | %FileCheck %s + +func g(_ f : (E) throws -> (U)) {} + +// CHECK: _T021conformance_multifile1tyyF +func t() { + g(E2.Filter) +} diff --git a/test/IRGen/enum_value_semantics.sil b/test/IRGen/enum_value_semantics.sil index 65b48c3a41c..71f88628ee3 100644 --- a/test/IRGen/enum_value_semantics.sil +++ b/test/IRGen/enum_value_semantics.sil @@ -456,7 +456,7 @@ bb0(%0 : $SinglePayloadNontrivial): // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds %T20enum_value_semantics22MultiPayloadNontrivialO, %T20enum_value_semantics22MultiPayloadNontrivialO* %0, i32 0, i32 1 // CHECK-NEXT: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i8* // CHECK-NEXT: [[TAG:%.*]] = load i8, i8* [[TAG_ADDR]], align 8 -// CHECK-NEXT: @_T020enum_value_semantics22MultiPayloadNontrivialOWy +// CHECK-NEXT: @_T020enum_value_semantics22MultiPayloadNontrivialOWe // CHECK-NEXT: ret void @@ -499,7 +499,7 @@ bb0(%0 : $SinglePayloadNontrivial): // CHECK-NEXT: [[PAYLOAD_0:%.*]] = load i64, i64* [[PAYLOAD_0_ADDR]], align 8 // CHECK-NEXT: [[PAYLOAD_1_ADDR:%.*]] = getelementptr // CHECK-NEXT: [[PAYLOAD_1:%.*]] = load i64, i64* [[PAYLOAD_1_ADDR]], align 8 -// CHECK: call void @_T020enum_value_semantics31MultiPayloadNontrivialSpareBitsOWy +// CHECK: call void @_T020enum_value_semantics31MultiPayloadNontrivialSpareBitsOWe // CHECK-NEXT: ret void diff --git a/test/IRGen/keypaths.sil b/test/IRGen/keypaths.sil index 851792fceeb..4b638ebde3b 100644 --- a/test/IRGen/keypaths.sil +++ b/test/IRGen/keypaths.sil @@ -1,4 +1,7 @@ -// RUN: %target-swift-frontend -emit-ir %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize +// RUN: rm -rf %t && mkdir -p %t +// -- Convert constants to decimal constants that LLVM will print +// RUN: %utils/chex.py < %s > %t/keypaths.sil +// RUN: %target-swift-frontend -emit-ir %s | %FileCheck %t/keypaths.sil --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize sil_stage canonical import Swift @@ -27,8 +30,9 @@ sil_vtable C {} // CHECK-SAME: [[WORD]] 0, // CHECK-SAME: %swift.type* (i8*)* // CHECK-SAME: %swift.type* (i8*)* -// -- 0x8000_0018 - instantiable in-line, size 4 -// CHECK-SAME: i32 -2147483644, +// -- instantiable in-line, size 4 +// CHECK-SAME: , +// CHECK-64-SAME: [4 x i8] zeroinitializer, // -- offset of S.x // CHECK-SAME: i32 0 }> @@ -37,8 +41,9 @@ sil_vtable C {} // CHECK-SAME: [[WORD]] 0, // CHECK-SAME: %swift.type* (i8*)* // CHECK-SAME: %swift.type* (i8*)* -// -- 0x8000_0018 - instantiable in-line, size 4 -// CHECK-SAME: i32 -2147483644, +// -- instantiable in-line, size 4 +// CHECK-SAME: , +// CHECK-64-SAME: [4 x i8] zeroinitializer, // -- offset of S.y // CHECK-32-SAME: i32 4 }> // CHECK-64-SAME: i32 8 }> @@ -48,8 +53,9 @@ sil_vtable C {} // CHECK-SAME: [[WORD]] 0, // CHECK-SAME: %swift.type* (i8*)* // CHECK-SAME: %swift.type* (i8*)* -// -- 0x8000_0018 - instantiable in-line, size 4 -// CHECK-SAME: i32 -2147483644, +// -- instantiable in-line, size 4 +// CHECK-SAME: , +// CHECK-64-SAME: [4 x i8] zeroinitializer, // -- offset of S.z // CHECK-32-SAME: i32 16 }> // CHECK-64-SAME: i32 32 }> @@ -59,63 +65,70 @@ sil_vtable C {} // CHECK-SAME: [[WORD]] 0, // CHECK-SAME: %swift.type* (i8*)* // CHECK-SAME: %swift.type* (i8*)* -// -- 0x8000_0018 - instantiable in-line, size 4 -// CHECK-SAME: i32 -2147483644, +// -- instantiable in-line, size 4 +// CHECK-SAME: , +// CHECK-64-SAME: [4 x i8] zeroinitializer, // -- 0x4000_0000 (class) + offset of C.x -// CHECK-32-SAME: i32 1073741836 }> -// CHECK-64-SAME: i32 1073741840 }> +// CHECK-32-SAME: }> +// CHECK-64-SAME: }> // -- %e: C.y // CHECK: [[KP_E:@keypath.*]] = private global <{ {{.*}} }> <{ // CHECK-SAME: [[WORD]] 0, // CHECK-SAME: %swift.type* (i8*)* // CHECK-SAME: %swift.type* (i8*)* -// -- 0x8000_0018 - instantiable in-line, size 4 -// CHECK-SAME: i32 -2147483644, +// -- instantiable in-line, size 4 +// CHECK-SAME: , +// CHECK-64-SAME: [4 x i8] zeroinitializer, // -- 0x4000_0000 (class) + offset of C.y -// CHECK-32-SAME: i32 1073741840 }> -// CHECK-64-SAME: i32 1073741848 }> +// CHECK-32-SAME: }> +// CHECK-64-SAME: }> // -- %f: C.z // CHECK: [[KP_F:@keypath.*]] = private global <{ {{.*}} }> <{ // CHECK-SAME: [[WORD]] 0, // CHECK-SAME: %swift.type* (i8*)* // CHECK-SAME: %swift.type* (i8*)* -// -- 0x8000_0018 - instantiable in-line, size 4 -// CHECK-SAME: i32 -2147483644, +// -- instantiable in-line, size 4 +// CHECK-SAME: , +// CHECK-64-SAME: [4 x i8] zeroinitializer, // -- 0x4000_0000 (class) + offset of C.z -// CHECK-32-SAME: i32 1073741852 }> -// CHECK-64-SAME: i32 1073741872 }> +// CHECK-32-SAME: }> +// CHECK-64-SAME: }> // -- %g: S.z.x // CHECK: [[KP_G:@keypath.*]] = private global <{ {{.*}} }> <{ // CHECK-SAME: [[WORD]] 0, // CHECK-SAME: %swift.type* (i8*)* // CHECK-SAME: %swift.type* (i8*)* -// -- 0x8000_0010 - instantiable in-line, size 12 -// CHECK-32-SAME: i32 -2147483636, -// -- 0x8000_0018 - instantiable in-line, size 16 -// CHECK-64-SAME: i32 -2147483632, +// -- instantiable in-line, size 12 +// CHECK-32-SAME: , +// -- instantiable in-line, size 20 +// CHECK-64-SAME: , +// CHECK-64-SAME: [4 x i8] zeroinitializer, // -- offset of S.z // CHECK-32-SAME: i32 16, // CHECK-64-SAME: i32 32, +// CHECK-64-SAME: [4 x i8] zeroinitializer, // CHECK: %swift.type* (i8*)* // -- 0x4000_0000 (class) + offset of C.x -// CHECK-32-SAME: i32 1073741836 }> -// CHECK-64-SAME: i32 1073741840 }> +// CHECK-32-SAME: }> +// CHECK-64-SAME: }> // -- %h: C.z.x // CHECK: [[KP_H:@keypath.*]] = private global <{ {{.*}} }> <{ // CHECK-SAME: [[WORD]] 0, // CHECK-SAME: %swift.type* (i8*)* // CHECK-SAME: %swift.type* (i8*)* -// -- 0x8000_0010 - instantiable in-line, size 12 -// CHECK-32-SAME: i32 -2147483636, -// -- 0x8000_0018 - instantiable in-line, size 16 -// CHECK-64-SAME: i32 -2147483632, +// -- instantiable in-line, size 12 +// CHECK-32-SAME: , +// -- instantiable in-line, size 20 +// CHECK-64-SAME: , +// CHECK-64-SAME: [4 x i8] zeroinitializer, // -- 0x4000_0000 (class) + offset of C.z -// CHECK-32-SAME: i32 1073741852, -// CHECK-64-SAME: i32 1073741872, +// CHECK-32-SAME: , +// CHECK-64-SAME: , +// CHECK-64-SAME: [4 x i8] zeroinitializer, // CHECK: %swift.type* (i8*)* // -- offset of S.x // CHECK-SAME: i32 0 }> @@ -125,12 +138,14 @@ sil_vtable C {} // CHECK-SAME: [[WORD]] 0, // CHECK-SAME: %swift.type* (i8*)* // CHECK-SAME: %swift.type* (i8*)* -// -- 0x8000_0014 - instantiable in-line, size 20 -// CHECK-64-SAME: i32 -2147483628, -// -- 0x8000_000c - instantiable in-line, size 12 -// CHECK-32-SAME: i32 -2147483636, -// -- 0x2000_0000 - computed, get-only, identified by function pointer, no args -// CHECK-SAME: i32 536870912, +// -- instantiable in-line, size 24 +// CHECK-64-SAME: , +// CHECK-64-SAME: [4 x i8] zeroinitializer, +// -- instantiable in-line, size 12 +// CHECK-32-SAME: , +// -- computed, get-only, identified by function pointer, no args +// CHECK-SAME: , +// CHECK-64-SAME: [4 x i8] zeroinitializer, // CHECK-SAME: void ()* @k_id, // CHECK-SAME: void (%TSi*, %T8keypaths1SV*)* @k_get }> @@ -139,12 +154,14 @@ sil_vtable C {} // CHECK-SAME: [[WORD]] 0, // CHECK-SAME: %swift.type* (i8*)* // CHECK-SAME: %swift.type* (i8*)* -// -- 0x8000_001c - instantiable in-line, size 28 -// CHECK-64-SAME: i32 -2147483620, -// -- 0x8000_0010 - instantiable in-line, size 16 -// CHECK-32-SAME: i32 -2147483632, -// -- 0x2a00_0000 - computed, settable, nonmutating, identified by vtable, no args -// CHECK-SAME: i32 704643072, +// -- instantiable in-line, size 32 +// CHECK-64-SAME: , +// CHECK-64-SAME: [4 x i8] zeroinitializer, +// -- instantiable in-line, size 16 +// CHECK-32-SAME: , +// -- computed, settable, nonmutating, identified by vtable, no args +// CHECK-SAME: , +// CHECK-64-SAME: [4 x i8] zeroinitializer, // CHECK-SAME: [[WORD]] // CHECK-SAME: void (%TSi*, %T8keypaths1CC**)* @l_get, // CHECK-SAME: void (%TSi*, %T8keypaths1CC**)* @l_set }> @@ -154,12 +171,14 @@ sil_vtable C {} // CHECK-SAME: [[WORD]] 0, // CHECK-SAME: %swift.type* (i8*)* // CHECK-SAME: %swift.type* (i8*)* -// -- 0x8000_001c - instantiable in-line, size 28 -// CHECK-64-SAME: i32 -2147483620, -// -- 0x8000_0010 - instantiable in-line, size 16 -// CHECK-32-SAME: i32 -2147483632, -// -- 0x3c00_0000 - computed, settable, nonmutating, identified by property offset, no args -// CHECK-SAME: i32 1006632960, +// -- instantiable in-line, size 32 +// CHECK-64-SAME: , +// CHECK-64-SAME: [4 x i8] zeroinitializer, +// -- instantiable in-line, size 16 +// CHECK-32-SAME: , +// -- computed, settable, nonmutating, identified by property offset, no args +// CHECK-SAME: , +// CHECK-64-SAME: [4 x i8] zeroinitializer, // CHECK-SAME: [[WORD]] // CHECK-SAME: void (%swift.function*, %T8keypaths1SV*)* @m_get, // CHECK-SAME: void (%swift.function*, %T8keypaths1SV*)* @m_set }> @@ -172,8 +191,9 @@ sil_vtable C {} // CHECK-SAME: %swift.type* (i8*)* [[I_GET_A:@[a-z_.0-9]+]], // -- size 8 // CHECK-SAME: i32 8, -// -- 0x1ffffffe - struct with runtime-resolved offset -// CHECK-SAME: i32 536870910, +// CHECK-64-SAME: [4 x i8] zeroinitializer, +// -- struct with runtime-resolved offset +// CHECK-SAME: , // CHECK-32-SAME: i32 12 }> // CHECK-64-SAME: i32 24 }> @@ -184,8 +204,9 @@ sil_vtable C {} // CHECK-SAME: %swift.type* (i8*)* [[J_GET_A:@[a-z_.0-9]+]], // -- size 8 // CHECK-SAME: i32 8, -// -- 0x1ffffffe - struct with runtime-resolved offset -// CHECK-SAME: i32 536870910, +// CHECK-64-SAME: [4 x i8] zeroinitializer, +// -- struct with runtime-resolved offset +// CHECK-SAME: , // CHECK-32-SAME: i32 16 }> // CHECK-64-SAME: i32 32 }> diff --git a/test/IRGen/keypaths_objc.sil b/test/IRGen/keypaths_objc.sil index 28e7d019abd..8ec51e2baee 100644 --- a/test/IRGen/keypaths_objc.sil +++ b/test/IRGen/keypaths_objc.sil @@ -6,6 +6,7 @@ import Foundation class C: NSObject { dynamic var x: NSString { get } + @sil_stored final var stored: Int override init() } @@ -18,6 +19,11 @@ sil @x_get : $@convention(thin) (@in C) -> @out NSString // CHECK-SAME: i32 536870914 // CHECK-SAME: i8** @"\01L_selector(x)" +// CHECK: [[KEYPATH_B:@keypath.*]] = private global +// -- 0x5ffffffd: class stored property with indirect offset +// CHECK-SAME: i32 1610612733, +// CHECK-SAME: @_T013keypaths_objc1CC6storedSivWvd + // CHECK-LABEL: define swiftcc void @objc_only_property() sil @objc_only_property : $@convention(thin) () -> () { entry: @@ -35,3 +41,10 @@ sil hidden @_T013keypaths_objc1CCACycfcTo : $@convention(objc_method) (@objc_met entry(%0 : $@objc_metatype C.Type): unreachable } + +sil @objc_stored_property : $@convention(thin) () -> () { +entry: + // CHECK: call %swift.refcounted* @swift_getKeyPath({{.*}} [[KEYPATH_B]] + %b = keypath $KeyPath, (objc "stored"; root $C; stored_property #C.stored : $Int) + unreachable +} diff --git a/test/IRGen/newtype.swift b/test/IRGen/newtype.swift index e1ad0516c97..ee50e60986f 100644 --- a/test/IRGen/newtype.swift +++ b/test/IRGen/newtype.swift @@ -158,3 +158,71 @@ class ObjCTest { return num } } + +// OPT-LABEL: _T07newtype6mutateyyF +public func mutate() { + // Check for a mismatch in indirectness of the swift_newtype and the Clang + // type. These pointers should be passed directly for non-mutating functions, + // rather than passing a pointer indirectly. I.e. only 1 overall level of + // indirection for non-mutating, 2 for mutating. + // + // OPT: [[TRefAlloca:%.+]] = alloca %struct.T*, + // OPT: [[TRef:%.+]] = tail call %struct.T* @create_T() + // OPT: store %struct.T* [[TRef]], %struct.T** [[TRefAlloca]], + var myT = create_T() + + // OPT: [[TRefConst:%.+]] = tail call %struct.T* @create_ConstT() + let myConstT = create_ConstT() + + // OPT: tail call void @mutate_TRef_Pointee(%struct.T* [[TRef]]) + myT.mutatePointee() + + // OPT: call void @mutate_TRef(%struct.T** nonnull [[TRefAlloca]]) + myT.mutate() + + // Since myT itself got mutated, now we have to reload from the alloca + // + // OPT: [[TRefReloaded:%.+]] = load %struct.T*, %struct.T** [[TRefAlloca]], + // OPT: call void @mutate_TRef_Pointee(%struct.T* [[TRefReloaded]]) + myT.mutatePointee() + + // OPT: call void @use_ConstT(%struct.T* [[TRefConst]]) + myConstT.use() + + // OPT: ret void +} + +// OPT-LABEL: _T07newtype9mutateRefyyF +public func mutateRef() { + // Check for a mismatch in indirectness of the swift_newtype and the Clang + // type. These pointer pointers should be passed directly, rather than passing + // a pointer pointer indirectly. I.e. only 2 overall levels of indirection for + // non-mutating, 3 for mutating. + // + // OPT: [[TRefRefAlloca:%.+]] = alloca %struct.T**, + // OPT: [[TRefRef:%.+]] = tail call %struct.T** @create_TRef() + // OPT: store %struct.T** [[TRefRef]], %struct.T*** [[TRefRefAlloca]] + var myTRef = create_TRef() + + // OPT: [[ConstTRefRef:%.+]] = tail call %struct.T** @create_ConstTRef() + let myConstTRef = create_ConstTRef() + + // OPT: tail call void @mutate_TRefRef_Pointee(%struct.T** [[TRefRef]]) + myTRef.mutatePointee() + + // OPT: call void @mutate_TRefRef(%struct.T*** nonnull [[TRefRefAlloca]]) + myTRef.mutate() + + // Since myTRef itself got mutated, now we have to reload from the alloca + // + // OPT: [[TRefReloaded:%.+]] = load %struct.T**, %struct.T*** [[TRefRefAlloca]] + // OPT: call void @mutate_TRefRef_Pointee(%struct.T** [[TRefReloaded]]) + myTRef.mutatePointee() + + // OPT: call void @use_ConstTRef(%struct.T** [[ConstTRefRef]]) + myConstTRef.use() + + // OPT: ret void +} + + diff --git a/test/IRGen/objc_attr_NSManaged.sil b/test/IRGen/objc_attr_NSManaged.sil index e648f55c021..66ee7f7b806 100644 --- a/test/IRGen/objc_attr_NSManaged.sil +++ b/test/IRGen/objc_attr_NSManaged.sil @@ -27,7 +27,7 @@ sil_vtable X {} // The getter/setter should not show up in the Swift metadata. /* FIXME: sil_vtable parser picks the wrong 'init' overload. Both vtable entries ought to be nonnull here. rdar://problem/19572342 */ -// CHECK: @_T019objc_attr_NSManaged10SwiftGizmoCMf = internal global <{ {{.*}} }> <{ void (%T19objc_attr_NSManaged10SwiftGizmoC*)* @_T019objc_attr_NSManaged10SwiftGizmoCfD, i8** @_T0BOWV, i64 ptrtoint (%objc_class* @"OBJC_METACLASS_$__TtC19objc_attr_NSManaged10SwiftGizmo" to i64), %objc_class* @"OBJC_CLASS_$_Gizmo", %swift.opaque* @_objc_empty_cache, %swift.opaque* null, i64 add (i64 ptrtoint ({ i32, i32, i32, i32, i8*, i8*, { i32, i32, [2 x { i8*, i8*, i8* }] }*, i8*, i8*, i8*, { i32, i32, [1 x { i8*, i8* }] }* }* @_DATA__TtC19objc_attr_NSManaged10SwiftGizmo to i64), i64 1), i32 1, i32 0, i32 16, i16 7, i16 0, i32 112, i32 16, {{.*}}* @_T019objc_attr_NSManaged10SwiftGizmoCMn {{.*}}, i8* null, %T19objc_attr_NSManaged10SwiftGizmoC* (i64, %T19objc_attr_NSManaged10SwiftGizmoC*)* @_T019objc_attr_NSManaged10SwiftGizmoCACSi7bellsOn_tcfc, i8* bitcast (void ()* @swift_deletedMethodError to i8*) }> +// CHECK: @_T019objc_attr_NSManaged10SwiftGizmoCMf = internal global <{ {{.*}} }> <{ void (%T19objc_attr_NSManaged10SwiftGizmoC*)* @_T019objc_attr_NSManaged10SwiftGizmoCfD, i8** @_T0BOWV, i64 ptrtoint (%objc_class* @"OBJC_METACLASS_$__TtC19objc_attr_NSManaged10SwiftGizmo" to i64), %objc_class* @"OBJC_CLASS_$_Gizmo", %swift.opaque* @_objc_empty_cache, %swift.opaque* null, i64 add (i64 ptrtoint ({ i32, i32, i32, i32, i8*, i8*, { i32, i32, [2 x { i8*, i8*, i8* }] }*, i8*, i8*, i8*, { i32, i32, [1 x { i8*, i8* }] }* }* @_DATA__TtC19objc_attr_NSManaged10SwiftGizmo to i64), i64 1), i32 1, i32 0, i32 8, i16 7, i16 0, i32 112, i32 16, {{.*}}* @_T019objc_attr_NSManaged10SwiftGizmoCMn {{.*}}, i8* null, %T19objc_attr_NSManaged10SwiftGizmoC* (i64, %T19objc_attr_NSManaged10SwiftGizmoC*)* @_T019objc_attr_NSManaged10SwiftGizmoCACSi7bellsOn_tcfc, i8* bitcast (void ()* @swift_deletedMethodError to i8*) }> @objc class SwiftGizmo : Gizmo { @objc @NSManaged var x: X diff --git a/test/IRGen/objc_subclass.swift b/test/IRGen/objc_subclass.swift index 64aa914cc76..602c56f421b 100644 --- a/test/IRGen/objc_subclass.swift +++ b/test/IRGen/objc_subclass.swift @@ -5,15 +5,15 @@ // REQUIRES: objc_interop // CHECK: [[SGIZMO:T13objc_subclass10SwiftGizmoC]] = type -// CHECK: [[TYPE:%swift.type]] = type -// CHECK: [[INT:%TSi]] = type <{ [[LLVM_PTRSIZE_INT:i(32|64)]] }> // CHECK: [[OBJC_CLASS:%objc_class]] = type // CHECK: [[OPAQUE:%swift.opaque]] = type +// CHECK: [[INT:%TSi]] = type <{ [[LLVM_PTRSIZE_INT:i(32|64)]] }> +// CHECK: [[TYPE:%swift.type]] = type // CHECK: [[GIZMO:%TSo5GizmoC]] = type opaque // CHECK: [[OBJC:%objc_object]] = type opaque -// CHECK-32: @_T013objc_subclass10SwiftGizmoC1xSivWvd = hidden global i32 12, align [[WORD_SIZE_IN_BYTES:4]] -// CHECK-64: @_T013objc_subclass10SwiftGizmoC1xSivWvd = hidden global i64 16, align [[WORD_SIZE_IN_BYTES:8]] +// CHECK-32: @_T013objc_subclass10SwiftGizmoC1xSivWvd = hidden global i32 4, align [[WORD_SIZE_IN_BYTES:4]] +// CHECK-64: @_T013objc_subclass10SwiftGizmoC1xSivWvd = hidden global i64 8, align [[WORD_SIZE_IN_BYTES:8]] // CHECK: @"OBJC_METACLASS_$__TtC13objc_subclass10SwiftGizmo" = hidden global [[OBJC_CLASS]] { [[OBJC_CLASS]]* @"OBJC_METACLASS_$_NSObject", [[OBJC_CLASS]]* @"OBJC_METACLASS_$_Gizmo", [[OPAQUE]]* @_objc_empty_cache, [[OPAQUE]]* null, [[LLVM_PTRSIZE_INT]] ptrtoint ({{.*}} @_METACLASS_DATA__TtC13objc_subclass10SwiftGizmo to [[LLVM_PTRSIZE_INT]]) } // CHECK: [[STRING_SWIFTGIZMO:@.*]] = private unnamed_addr constant [32 x i8] c"_TtC13objc_subclass10SwiftGizmo\00" @@ -183,8 +183,8 @@ // CHECK-32: @_DATA__TtC13objc_subclass10SwiftGizmo = private constant { {{.*}}* } { // CHECK-32: i32 132, -// CHECK-32: i32 12, -// CHECK-32: i32 16, +// CHECK-32: i32 4, +// CHECK-32: i32 8, // CHECK-32: i8* null, // CHECK-32: i8* getelementptr inbounds ([{{[0-9]+}} x i8], [{{[0-9]+}} x i8]* [[STRING_SWIFTGIZMO]], i32 0, i32 0), // CHECK-32: @_INSTANCE_METHODS__TtC13objc_subclass10SwiftGizmo, @@ -196,8 +196,8 @@ // CHECK-64: @_DATA__TtC13objc_subclass10SwiftGizmo = private constant { {{.*}}* } { // CHECK-64: i32 132, +// CHECK-64: i32 8, // CHECK-64: i32 16, -// CHECK-64: i32 24, // CHECK-64: i32 0, // CHECK-64: i8* null, // CHECK-64: i8* getelementptr inbounds ([{{[0-9]+}} x i8], [{{[0-9]+}} x i8]* [[STRING_SWIFTGIZMO]], i64 0, i64 0), diff --git a/test/IRGen/partial_apply.sil b/test/IRGen/partial_apply.sil index 5c4af066cf9..c10892a1757 100644 --- a/test/IRGen/partial_apply.sil +++ b/test/IRGen/partial_apply.sil @@ -365,7 +365,8 @@ sil public_external @partial_empty_box : $@convention(thin) (@owned <τ_0_0> { v // CHECK-LABEL: define{{( protected)?}} swiftcc void @empty_box() sil @empty_box : $@convention(thin) () -> () { entry: - // CHECK: store %swift.refcounted* null + // CHECK: [[BOX:%.*]] = call {{.*}}swift_allocEmptyBox + // CHECK: store %swift.refcounted* [[BOX]] // CHECK: store %swift.opaque* undef %b = alloc_box $<τ_0_0> { var τ_0_0 } <()> %ba = project_box %b : $<τ_0_0> { var τ_0_0 } <()>, 0 diff --git a/test/Index/kinds.swift b/test/Index/kinds.swift index 8948202274f..a831a9ec6e5 100644 --- a/test/Index/kinds.swift +++ b/test/Index/kinds.swift @@ -37,6 +37,9 @@ struct AStruct { return base } } + // CHECK: [[@LINE-20]]:13 | param/Swift | index | {{.*}} | Def,RelChild | rel: 1 + // CHECK: [[@LINE-21]]:20 | struct/Swift | Int | {{.*}} | Ref | rel: 0 + // CHECK: [[@LINE-22]]:28 | struct/Swift | Int | {{.*}} | Ref | rel: 0 } // Class diff --git a/test/Index/roles.swift b/test/Index/roles.swift index dcf165f964f..d215d65078f 100644 --- a/test/Index/roles.swift +++ b/test/Index/roles.swift @@ -226,7 +226,7 @@ protocol X { var reqProp: Int { get } // CHECK: [[@LINE-1]]:7 | instance-property/Swift | reqProp | [[reqProp_USR:.*]] | Def,RelChild | rel: 1 // CHECK: [[@LINE-2]]:22 | instance-method/acc-get/Swift | getter:reqProp | {{.*}} | Def,Dyn,RelChild,RelAcc | rel: 1 - // CHECK-NEXT RelChild,RelAcc | instance-property/Swift | reqProp_USR | [[reqProp_USR]] + // CHECK-NEXT: RelChild,RelAcc | instance-property/Swift | reqProp | [[reqProp_USR]] } protocol Y {} diff --git a/test/Inputs/clang-importer-sdk/usr/include/Foundation.h b/test/Inputs/clang-importer-sdk/usr/include/Foundation.h index 43b44c0d4f3..60e92a355e3 100644 --- a/test/Inputs/clang-importer-sdk/usr/include/Foundation.h +++ b/test/Inputs/clang-importer-sdk/usr/include/Foundation.h @@ -1100,3 +1100,13 @@ typedef enum __attribute__((ns_error_domain(FictionalServerErrorDomain))) Fictio - (void)bleach:(Coat * _Nonnull)garment; - (Coat * _Nonnull)dry; @end + +@interface NSLaundromat : NSObject +@end + +extern NSString * const NSLaundryErrorDomain; + +typedef enum __attribute__((ns_error_domain(NSLaundryErrorDomain))) __attribute__((swift_name("NSLaundromat.Error"))) NSLaundryErrorCode { + NSLaundryErrorTooMuchSoap = 1, + NSLaundryErrorCatInWasher = 2 +}; diff --git a/test/Inputs/comment_to_something_conversion.swift b/test/Inputs/comment_to_something_conversion.swift index 7c043c41856..655a2cac489 100644 --- a/test/Inputs/comment_to_something_conversion.swift +++ b/test/Inputs/comment_to_something_conversion.swift @@ -477,3 +477,15 @@ public func localizationKeyShouldNotAppearInDocComments() {} /// - LocalizationKey: ABC public func localizationKeyShouldNotAppearInDocComments2() {} // CHECK: DocCommentAsXML=[localizationKeyShouldNotAppearInDocComments2()s:14comment_to_xml44localizationKeyShouldNotAppearInDocComments2yyFpublic func localizationKeyShouldNotAppearInDocComments2()] + +/// Brief. +/// +/// - Tag: +/// - Tag: +/// - Tag: Tag_A +/// - Tag: Tag B +/// - Tag: Dedupe tag +/// - Tag: Dedupe tag +/// - TAG: TAG_C +public func tags() {} +// CHECK: DocCommentAsXML=[tags()s:14comment_to_xml4tagsyyFpublic func tags()Brief.Tag_ATag BDedupe tagTAG_C] diff --git a/test/Interpreter/SDK/check_class_for_archiving_log.swift b/test/Interpreter/SDK/check_class_for_archiving_log.swift new file mode 100644 index 00000000000..cabc0628a1f --- /dev/null +++ b/test/Interpreter/SDK/check_class_for_archiving_log.swift @@ -0,0 +1,173 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %s -module-name=_Test -import-objc-header %S/Inputs/check_class_for_archiving.h -o %t/a.out +// RUN: %target-run %t/a.out 2>&1 | %FileCheck %s + +// REQUIRES: executable_test +// REQUIRES: objc_interop + +// This test doesn't use StdlibUnittest because it's primarily concerned with +// checking the presence and absence of output. + +import Foundation + +class SwiftClass {} + +func checkArchiving(_ cls: AnyObject.Type) { + NSKeyedUnarchiver._swift_checkClassAndWarnForKeyedArchiving(cls, operation: 0) +} +func checkUnarchiving(_ cls: AnyObject.Type) { + NSKeyedUnarchiver._swift_checkClassAndWarnForKeyedArchiving(cls, operation: 1) +} + +func mark(line: Int32 = #line) { + NSLog("--%d--", line) +} + +mark() // CHECK: --[[@LINE]]-- +checkArchiving(SwiftClass.self) +mark() // CHECK-NEXT: --[[@LINE]]-- + + +private class ArchivedTwice {} + +checkArchiving(ArchivedTwice.self) +// CHECK-NEXT: Attempting to archive Swift class '_Test.(ArchivedTwice in {{.+}})' with mangled runtime name '_TtC{{.+[0-9]+}}ArchivedTwice' +// CHECK-NEXT: @objc(_TtC{{.+[0-9]+}}ArchivedTwice) +// CHECK-NEXT: @objc(ABCArchivedTwice) +mark() // CHECK-NEXT: --[[@LINE]]-- +checkArchiving(ArchivedTwice.self) +mark() // CHECK-NEXT: --[[@LINE]]-- + +private class UnarchivedTwice {} + +checkUnarchiving(UnarchivedTwice.self) +// CHECK-NEXT: Attempting to unarchive Swift class '_Test.(UnarchivedTwice in {{.+}})' with mangled runtime name '_TtC{{.+[0-9]+}}UnarchivedTwice' +// CHECK-NEXT: @objc(_TtC{{.+[0-9]+}}UnarchivedTwice) +// CHECK-NEXT: @objc(ABCUnarchivedTwice) +mark() // CHECK-NEXT: --[[@LINE]]-- +checkUnarchiving(UnarchivedTwice.self) +mark() // CHECK-NEXT: --[[@LINE]]-- + +private class ArchivedThenUnarchived {} + +checkArchiving(ArchivedThenUnarchived.self) +// CHECK-NEXT: Attempting to archive Swift class '_Test.(ArchivedThenUnarchived in {{.+}})' with mangled runtime name '_TtC{{.+[0-9]+}}ArchivedThenUnarchived' +// CHECK-NEXT: @objc(_TtC{{.+[0-9]+}}ArchivedThenUnarchived) +// CHECK-NEXT: @objc(ABCArchivedThenUnarchived) +mark() // CHECK-NEXT: --[[@LINE]]-- +checkUnarchiving(ArchivedThenUnarchived.self) +mark() // CHECK-NEXT: --[[@LINE]]-- + +private class UnarchivedThenArchived {} + +checkUnarchiving(UnarchivedThenArchived.self) +// CHECK-NEXT: Attempting to unarchive Swift class '_Test.(UnarchivedThenArchived in {{.+}})' with mangled runtime name '_TtC{{.+[0-9]+}}UnarchivedThenArchived' +// CHECK-NEXT: @objc(_TtC{{.+[0-9]+}}UnarchivedThenArchived) +// CHECK-NEXT: @objc(ABCUnarchivedThenArchived) +mark() // CHECK-NEXT: --[[@LINE]]-- +checkArchiving(UnarchivedThenArchived.self) +mark() // CHECK-NEXT: --[[@LINE]]-- + +class Outer { + class ArchivedTwice {} + class UnarchivedTwice {} + class ArchivedThenUnarchived {} + class UnarchivedThenArchived {} +} + +checkArchiving(Outer.ArchivedTwice.self) +// CHECK-NEXT: Attempting to archive Swift class '_Test.Outer.ArchivedTwice' +// CHECK-NEXT: @objc(_TtC{{.+[0-9]+}}ArchivedTwice) +// CHECK-NEXT: @objc(ABCArchivedTwice) +mark() // CHECK-NEXT: --[[@LINE]]-- +checkArchiving(Outer.ArchivedTwice.self) +mark() // CHECK-NEXT: --[[@LINE]]-- + +checkUnarchiving(Outer.UnarchivedTwice.self) +// CHECK-NEXT: Attempting to unarchive Swift class '_Test.Outer.UnarchivedTwice' +// CHECK-NEXT: @objc(_TtC{{.+[0-9]+}}UnarchivedTwice) +// CHECK-NEXT: @objc(ABCUnarchivedTwice) +mark() // CHECK-NEXT: --[[@LINE]]-- +checkUnarchiving(Outer.UnarchivedTwice.self) +mark() // CHECK-NEXT: --[[@LINE]]-- + +checkArchiving(Outer.ArchivedThenUnarchived.self) +// CHECK-NEXT: Attempting to archive Swift class '_Test.Outer.ArchivedThenUnarchived' +// CHECK-NEXT: @objc(_TtC{{.+[0-9]+}}ArchivedThenUnarchived) +// CHECK-NEXT: @objc(ABCArchivedThenUnarchived) +mark() // CHECK-NEXT: --[[@LINE]]-- +checkUnarchiving(Outer.ArchivedThenUnarchived.self) +mark() // CHECK-NEXT: --[[@LINE]]-- + +checkUnarchiving(Outer.UnarchivedThenArchived.self) +// CHECK-NEXT: Attempting to unarchive Swift class '_Test.Outer.UnarchivedThenArchived' +// CHECK-NEXT: @objc(_TtC{{.+[0-9]+}}UnarchivedThenArchived) +// CHECK-NEXT: @objc(ABCUnarchivedThenArchived) +mark() // CHECK-NEXT: --[[@LINE]]-- +checkArchiving(Outer.UnarchivedThenArchived.self) +mark() // CHECK-NEXT: --[[@LINE]]-- + + +private class 日本語 {} + +checkArchiving(日本語.self) +// CHECK-NEXT: Attempting to archive Swift class '_Test.(日本語 in {{.+}})' +// CHECK-NEXT: @objc(_TtC{{.+[0-9]+}}9日本語) +// CHECK-NEXT: @objc(ABCMyModel) +mark() // CHECK-NEXT: --[[@LINE]]-- +checkArchiving(日本語.self) +mark() // CHECK-NEXT: --[[@LINE]]-- + + +class ArchivedTwiceGeneric {} + +checkArchiving(ArchivedTwiceGeneric.self) +// CHECK-NEXT: Attempting to archive generic Swift class '_Test.ArchivedTwiceGeneric' with mangled runtime name '_TtGC5_Test20ArchivedTwiceGenericSi_' +// CHECK-NEXT: NSKeyedUnarchiver.setClass(_:forClassName:) +// CHECK-SAME: _TtGC5_Test20ArchivedTwiceGenericSi_ +// CHECK-NEXT: NSKeyedArchiver.setClassName(_:for:) +mark() // CHECK-NEXT: --[[@LINE]]-- +checkArchiving(ArchivedTwiceGeneric.self) +mark() // CHECK-NEXT: --[[@LINE]]-- + +checkArchiving(ArchivedTwiceGeneric.self) +// CHECK-NEXT: Attempting to archive generic Swift class '_Test.ArchivedTwiceGeneric<__ObjC.NSObject>' with mangled runtime name '_TtGC5_Test20ArchivedTwiceGenericCSo8NSObject_' +// CHECK-NEXT: NSKeyedUnarchiver.setClass(_:forClassName:) +// CHECK-SAME: _TtGC5_Test20ArchivedTwiceGenericCSo8NSObject_ +// CHECK-NEXT: NSKeyedArchiver.setClassName(_:for:) +mark() // CHECK-NEXT: --[[@LINE]]-- +checkArchiving(ArchivedTwiceGeneric.self) +mark() // CHECK-NEXT: --[[@LINE]]-- + +class UnarchivedTwiceGeneric {} + +checkUnarchiving(UnarchivedTwiceGeneric.self) +// CHECK-NEXT: Attempting to unarchive generic Swift class '_Test.UnarchivedTwiceGeneric' with mangled runtime name '_TtGC5_Test22UnarchivedTwiceGenericSi_' +// CHECK-NEXT: NSKeyedUnarchiver.setClass(_:forClassName:) +// CHECK-SAME: _TtGC5_Test22UnarchivedTwiceGenericSi_ +// CHECK-NEXT: NSKeyedArchiver.setClassName(_:for:) +mark() // CHECK-NEXT: --[[@LINE]]-- +checkUnarchiving(UnarchivedTwiceGeneric.self) +mark() // CHECK-NEXT: --[[@LINE]]-- + +class ArchivedThenUnarchivedGeneric {} + +checkArchiving(ArchivedThenUnarchivedGeneric.self) +// CHECK-NEXT: Attempting to archive generic Swift class '_Test.ArchivedThenUnarchivedGeneric' with mangled runtime name '_TtGC5_Test29ArchivedThenUnarchivedGenericSi_' +// CHECK-NEXT: NSKeyedUnarchiver.setClass(_:forClassName:) +// CHECK-SAME: _TtGC5_Test29ArchivedThenUnarchivedGenericSi_ +// CHECK-NEXT: NSKeyedArchiver.setClassName(_:for:) +mark() // CHECK-NEXT: --[[@LINE]]-- +checkUnarchiving(ArchivedThenUnarchivedGeneric.self) +mark() // CHECK-NEXT: --[[@LINE]]-- + +class UnarchivedThenArchivedGeneric {} + +checkUnarchiving(UnarchivedThenArchivedGeneric.self) +// CHECK-NEXT: Attempting to unarchive generic Swift class '_Test.UnarchivedThenArchivedGeneric' with mangled runtime name '_TtGC5_Test29UnarchivedThenArchivedGenericSi_' +// CHECK-NEXT: NSKeyedUnarchiver.setClass(_:forClassName:) +// CHECK-SAME: _TtGC5_Test29UnarchivedThenArchivedGenericSi_ +// CHECK-NEXT: NSKeyedArchiver.setClassName(_:for:) +mark() // CHECK-NEXT: --[[@LINE]]-- +checkArchiving(UnarchivedThenArchivedGeneric.self) +mark() // CHECK-NEXT: --[[@LINE]]-- diff --git a/test/Interpreter/SDK/objc_keypath.swift b/test/Interpreter/SDK/objc_keypath.swift index 5a7c6d757bb..30c1758b155 100644 --- a/test/Interpreter/SDK/objc_keypath.swift +++ b/test/Interpreter/SDK/objc_keypath.swift @@ -36,10 +36,10 @@ band.members = [Person(firstName: "John", lastName: "Lennon"), // CHECK: ===Members=== // CHECK-NEXT: ( // CHECK-NEXT: Lennon, John -// CHECK-NEXT McCartney, Paul, -// CHECK-NEXT Harrison, George, -// CHECK-NEXT Star, Ringo -// CHECK-NEXT) +// CHECK-NEXT: McCartney, Paul +// CHECK-NEXT: Harrison, George +// CHECK-NEXT: Star, Ringo +// CHECK-NEXT: ) print("===Members===") print((band.value(forKeyPath: #keyPath(Band.members))! as AnyObject).description) diff --git a/test/Interpreter/enforce_exclusive_access.swift b/test/Interpreter/enforce_exclusive_access.swift index 23d74e84552..40fd5bf1755 100644 --- a/test/Interpreter/enforce_exclusive_access.swift +++ b/test/Interpreter/enforce_exclusive_access.swift @@ -184,6 +184,121 @@ ExclusiveAccessTestSuite.test("PerThreadEnforcement") { } } +// Helpers +func doOne(_ f: () -> ()) { f() } +func doTwo(_ f1: ()->(), _ f2: ()->()) { f1(); f2() } + +// No crash. +ExclusiveAccessTestSuite.test("WriteNoescapeWrite") { + var x = 3 + let c = { x = 7 } + // Inside may-escape closure `c`: [read] [dynamic] + // Inside never-escape closure: [modify] [dynamic] + doTwo(c, { x = 42 }) + _blackHole(x) +} + +// No crash. +ExclusiveAccessTestSuite.test("InoutReadEscapeRead") { + var x = 3 + let c = { let y = x; _blackHole(y) } + readAndPerform(&x, closure: c) + _blackHole(x) +} + +ExclusiveAccessTestSuite.test("InoutReadEscapeWrite") + .skip(.custom( + { _isFastAssertConfiguration() }, + reason: "this trap is not guaranteed to happen in -Ounchecked")) + .crashOutputMatches("Previous access (a read) started at") + .crashOutputMatches("Current access (a modification) started at") + .code +{ + var x = 3 + let c = { x = 42 } + expectCrashLater() + readAndPerform(&x, closure: c) + _blackHole(x) +} + +ExclusiveAccessTestSuite.test("InoutWriteEscapeRead") + .skip(.custom( + { _isFastAssertConfiguration() }, + reason: "this trap is not guaranteed to happen in -Ounchecked")) + .crashOutputMatches("Previous access (a modification) started at") + .crashOutputMatches("Current access (a read) started at") + .code +{ + var x = 3 + let c = { let y = x; _blackHole(y) } + expectCrashLater() + modifyAndPerform(&x, closure: c) + _blackHole(x) +} + +ExclusiveAccessTestSuite.test("InoutWriteEscapeWrite") + .skip(.custom( + { _isFastAssertConfiguration() }, + reason: "this trap is not guaranteed to happen in -Ounchecked")) + .crashOutputMatches("Previous access (a modification) started at") + .crashOutputMatches("Current access (a modification) started at") + .code +{ + var x = 3 + let c = { x = 42 } + expectCrashLater() + modifyAndPerform(&x, closure: c) + _blackHole(x) +} + +// No crash. +ExclusiveAccessTestSuite.test("InoutReadNoescapeRead") { + var x = 3 + let c = { let y = x; _blackHole(y) } + doOne { readAndPerform(&x, closure: c) } +} + +ExclusiveAccessTestSuite.test("InoutReadNoescapeWrite") + .skip(.custom( + { _isFastAssertConfiguration() }, + reason: "this trap is not guaranteed to happen in -Ounchecked")) + .crashOutputMatches("Previous access (a read) started at") + .crashOutputMatches("Current access (a modification) started at") + .code +{ + var x = 3 + let c = { x = 7 } + expectCrashLater() + doOne { readAndPerform(&x, closure: c) } +} + +ExclusiveAccessTestSuite.test("InoutWriteEscapeRead") + .skip(.custom( + { _isFastAssertConfiguration() }, + reason: "this trap is not guaranteed to happen in -Ounchecked")) + .crashOutputMatches("Previous access (a modification) started at") + .crashOutputMatches("Current access (a read) started at") + .code +{ + var x = 3 + let c = { let y = x; _blackHole(y) } + expectCrashLater() + doOne { modifyAndPerform(&x, closure: c) } +} + +ExclusiveAccessTestSuite.test("InoutWriteEscapeWrite") + .skip(.custom( + { _isFastAssertConfiguration() }, + reason: "this trap is not guaranteed to happen in -Ounchecked")) + .crashOutputMatches("Previous access (a modification) started at") + .crashOutputMatches("Current access (a modification) started at") + .code +{ + var x = 3 + let c = { x = 7 } + expectCrashLater() + doOne { modifyAndPerform(&x, closure: c) } +} runAllTests() diff --git a/test/Interpreter/enum.swift b/test/Interpreter/enum.swift index 50c9eb8e10b..225af0551cb 100644 --- a/test/Interpreter/enum.swift +++ b/test/Interpreter/enum.swift @@ -553,5 +553,50 @@ presentEitherOr(EitherOr<(), String>.Right("foo")) // CHECK-NEXT: Right(foo) // CHECK-NEXT: Right(foo) presentEitherOrsOf(t: (), u: "foo") +// SR-5148 +enum Payload { + case email +} +enum Test { + case a + indirect case b(Payload) +} + +@inline(never) +func printA() { + print("an a") +} + +@inline(never) +func printB() { + print("an b") +} + +@inline(never) +func testCase(_ testEmail: Test) { + switch testEmail { + case .a: + printA() + case .b: + printB() + } +} + +@inline(never) +func createTestB() -> Test { + return Test.b(.email) +} + +@inline(never) +func createTestA() -> Test { + return Test.a +} + +// CHECK-NEXT: an b +testCase(createTestB()) +// CHECK-NEXT: b(a.Payload.email) +print(createTestB()) +// CHECK-NEXT: a +print(createTestA()) // CHECK-NEXT: done print("done") diff --git a/test/Interpreter/simd.swift b/test/Interpreter/simd.swift new file mode 100644 index 00000000000..b1bd7e8c18e --- /dev/null +++ b/test/Interpreter/simd.swift @@ -0,0 +1,31 @@ +// RUN: %target-run-simple-swift | %FileCheck %s +// REQUIRES: executable_test +// REQUIRES: OS=macosx + +import simd + +public struct Vector3f { + var f3: float3 + init() { + f3 = float3(0, 1, 2) + } +} + +public struct TwoFloat { + var f0 : Float + var f1 : Float + init() { + f0 = 0.0 + f1 = 1.0 + } +} + +public func test() -> (Vector3f, TwoFloat) { + let v = Vector3f() + let y = TwoFloat() + let r = (v, y) + return r +} + +// CHECK: (main.Vector3f(f3: float3(0.0, 1.0, 2.0)), main.TwoFloat(f0: 0.0, f1: 1.0)) +print(test()) diff --git a/test/Migrator/DoubleEditAPI.json b/test/Migrator/DoubleEditAPI.json index 150214c1013..a58cc6e6423 100644 --- a/test/Migrator/DoubleEditAPI.json +++ b/test/Migrator/DoubleEditAPI.json @@ -1,4 +1,11 @@ [ + { + "DiffItemKind": "TypeMemberDiffItem", + "Usr": "c:@E@FooComparisonResult@FooOrderedAscending", + "OldPrintedName": "FooOrderedAscending", + "NewPrintedName": "orderedAscending", + "NewTypeName": "FooComparisonResult" + }, { "DiffItemKind": "TypeMemberDiffItem", "Usr": "c:@SA@SomeItemSet", diff --git a/test/Migrator/Inputs/API.json b/test/Migrator/Inputs/API.json index 0dc19aca7a0..8749acd319c 100644 --- a/test/Migrator/Inputs/API.json +++ b/test/Migrator/Inputs/API.json @@ -127,6 +127,17 @@ "RightComment": "", "ModuleName": "bar" }, + { + "DiffItemKind": "CommonDiffItem", + "NodeKind": "Function", + "NodeAnnotation": "SetterToProperty", + "ChildIndex": "0", + "LeftUsr": "c:objc(cs)PropertyUserInterface(im)setURL:", + "LeftComment": "", + "RightUsr": "", + "RightComment": "", + "ModuleName": "bar" + }, { "DiffItemKind": "CommonDiffItem", "NodeKind": "Function", diff --git a/test/Migrator/Inputs/Cities.swift b/test/Migrator/Inputs/Cities.swift index 7b4d36736ac..62da790eeb4 100644 --- a/test/Migrator/Inputs/Cities.swift +++ b/test/Migrator/Inputs/Cities.swift @@ -9,6 +9,9 @@ open class Cities { open func buderim() -> Cities? { return Cities(x: 1) } open func noosa() -> [[String : Cities]?] { return [] } open func maroochy(x: Int?, y: Int?) {} + public struct CityKind { + static public let Town = 1 + } } public protocol ExtraCities { diff --git a/test/Migrator/Inputs/qualified.json b/test/Migrator/Inputs/qualified.json index cda5d4c61f0..9a942eda2ec 100644 --- a/test/Migrator/Inputs/qualified.json +++ b/test/Migrator/Inputs/qualified.json @@ -22,5 +22,13 @@ "OldTypeName": "FooComparisonResult", "NewPrintedName": "NewFooOrderedSame", "NewTypeName": "NewFooComparisonResult" + }, + { + "DiffItemKind": "TypeMemberDiffItem", + "Usr": "s:6CitiesAAC8CityKindV4TownSivZ", + "OldPrintedName": "town", + "OldTypeName": "Cities.CityKind", + "NewPrintedName": "NewTown", + "NewTypeName": "NewCityKind" } ] diff --git a/test/Migrator/mock-sdk/Bar.framework/Headers/Bar.h b/test/Migrator/mock-sdk/Bar.framework/Headers/Bar.h index e327f433b44..f016107d26f 100644 --- a/test/Migrator/mock-sdk/Bar.framework/Headers/Bar.h +++ b/test/Migrator/mock-sdk/Bar.framework/Headers/Bar.h @@ -25,6 +25,7 @@ enum BarForwardDeclaredEnum { - (int) field; - (int * _Nullable) field2; - (void) setField:(int)info; +- (void) setURL:(int)url; + (int) fieldPlus; + (void) methodPlus:(int)info; + (void) methodPlus; diff --git a/test/Migrator/no_ast_passes_after_swift4.swift b/test/Migrator/no_ast_passes_after_swift4.swift new file mode 100644 index 00000000000..6c2d80590c0 --- /dev/null +++ b/test/Migrator/no_ast_passes_after_swift4.swift @@ -0,0 +1,9 @@ +// REQUIRES: objc_interop +// RUN: %empty-directory(%t) && %target-swift-frontend -c -update-code -primary-file %s -F %S/mock-sdk -api-diff-data-file %S/Inputs/DoubleEditAPI.json -emit-migrated-file-path %t/no_ast_passes_after_swift4.swift.result -emit-remap-file-path %t/no_ast_passes_after_swift4.swift.remap -o /dev/null -swift-version 4 +// RUN: diff -u %S/no_ast_passes_after_swift4.swift.expected %t/no_ast_passes_after_swift4.swift.result +// RUN: %target-swift-frontend -typecheck -F %S/mock-sdk -swift-version 4 %t/no_ast_passes_after_swift4.swift.result + +import Bar +func foo() -> FooComparisonResult { + return FooComparisonResult.orderedAscending +} diff --git a/test/Migrator/no_ast_passes_after_swift4.swift.expected b/test/Migrator/no_ast_passes_after_swift4.swift.expected new file mode 100644 index 00000000000..6c2d80590c0 --- /dev/null +++ b/test/Migrator/no_ast_passes_after_swift4.swift.expected @@ -0,0 +1,9 @@ +// REQUIRES: objc_interop +// RUN: %empty-directory(%t) && %target-swift-frontend -c -update-code -primary-file %s -F %S/mock-sdk -api-diff-data-file %S/Inputs/DoubleEditAPI.json -emit-migrated-file-path %t/no_ast_passes_after_swift4.swift.result -emit-remap-file-path %t/no_ast_passes_after_swift4.swift.remap -o /dev/null -swift-version 4 +// RUN: diff -u %S/no_ast_passes_after_swift4.swift.expected %t/no_ast_passes_after_swift4.swift.result +// RUN: %target-swift-frontend -typecheck -F %S/mock-sdk -swift-version 4 %t/no_ast_passes_after_swift4.swift.result + +import Bar +func foo() -> FooComparisonResult { + return FooComparisonResult.orderedAscending +} diff --git a/test/Migrator/no_duplicate_aarch64_use_tbi.swift b/test/Migrator/no_duplicate_aarch64_use_tbi.swift index 75b470849e3..1eb779d2096 100644 --- a/test/Migrator/no_duplicate_aarch64_use_tbi.swift +++ b/test/Migrator/no_duplicate_aarch64_use_tbi.swift @@ -8,7 +8,7 @@ public func foo(_ f: (Void) -> ()) {} -// CHECK-REMAP: "offset": 671, +// CHECK-REMAP: "offset": 673, // CHECK-REMAP: "remove": 5, // CHECK-REMAP: "text": "(" diff --git a/test/Migrator/no_extraneous_argument_labels.swift.expected b/test/Migrator/no_extraneous_argument_labels.swift.expected index 0fdaed33768..c4a9ce30a5f 100644 --- a/test/Migrator/no_extraneous_argument_labels.swift.expected +++ b/test/Migrator/no_extraneous_argument_labels.swift.expected @@ -7,6 +7,6 @@ func foo(_ oc: [String]) { var args: [String] = [] let dictionary: [String: String] = [:] args.append(contentsOf: oc.map { orderedColumn in - dictionary.first { let (column, value) = $0; return true }!.value + dictionary.first { (column, value) in true }!.value }) } diff --git a/test/Migrator/pre_fixit_pass.swift b/test/Migrator/pre_fixit_pass.swift index 2b9927fc1fb..72a2e941b06 100644 --- a/test/Migrator/pre_fixit_pass.swift +++ b/test/Migrator/pre_fixit_pass.swift @@ -11,5 +11,6 @@ Old() func foo(_ a : PropertyUserInterface) { a.setField(1) + a.setURL(1) _ = a.field() } diff --git a/test/Migrator/pre_fixit_pass.swift.expected b/test/Migrator/pre_fixit_pass.swift.expected index 5fb0bd951a7..e14994861c7 100644 --- a/test/Migrator/pre_fixit_pass.swift.expected +++ b/test/Migrator/pre_fixit_pass.swift.expected @@ -10,6 +10,7 @@ struct Old {} New() func foo(_ a : PropertyUserInterface) { - a.Field = 1 + a.field = 1 + a.url = 1 _ = a.field } diff --git a/test/Migrator/property.swift b/test/Migrator/property.swift index c7d40951a66..622e4774138 100644 --- a/test/Migrator/property.swift +++ b/test/Migrator/property.swift @@ -7,6 +7,7 @@ import Bar func foo(_ a : PropertyUserInterface) { a.setField(1) + a.setURL(1) _ = a.field() } diff --git a/test/Migrator/property.swift.expected b/test/Migrator/property.swift.expected index 7b0943abcc3..9b79ad05ded 100644 --- a/test/Migrator/property.swift.expected +++ b/test/Migrator/property.swift.expected @@ -6,7 +6,8 @@ import Bar func foo(_ a : PropertyUserInterface) { - a.Field = 1 + a.field = 1 + a.url = 1 _ = a.field } diff --git a/test/Migrator/qualified-replacement.swift b/test/Migrator/qualified-replacement.swift index 41a8f1fb22e..e0d7ab16808 100644 --- a/test/Migrator/qualified-replacement.swift +++ b/test/Migrator/qualified-replacement.swift @@ -1,11 +1,15 @@ // REQUIRES: objc_interop -// RUN: %empty-directory(%t) && %target-swift-frontend -c -update-code -primary-file %s -F %S/mock-sdk -api-diff-data-file %S/Inputs/qualified.json -emit-migrated-file-path %t/qualified-replacement.swift.result -emit-remap-file-path %t/qualified-replacement.swift.remap -o /dev/null +// RUN: %empty-directory(%t.mod) +// RUN: %target-swift-frontend -emit-module -o %t.mod/Cities.swiftmodule %S/Inputs/Cities.swift -module-name Cities -parse-as-library +// RUN: %empty-directory(%t) && %target-swift-frontend -c -update-code -primary-file %s -F %S/mock-sdk -I %t.mod -api-diff-data-file %S/Inputs/qualified.json -emit-migrated-file-path %t/qualified-replacement.swift.result -emit-remap-file-path %t/qualified-replacement.swift.remap -o /dev/null // RUN: diff -u %S/qualified-replacement.swift.expected %t/qualified-replacement.swift.result +import Cities import Bar func foo() { _ = PropertyUserInterface.fieldPlus PropertyUserInterface.methodPlus(1) _ = FooComparisonResult.orderedSame let _ : FooComparisonResult = .orderedSame + _ = Cities.CityKind.Town } diff --git a/test/Migrator/qualified-replacement.swift.expected b/test/Migrator/qualified-replacement.swift.expected index 3c1bc948228..4fb99aeae09 100644 --- a/test/Migrator/qualified-replacement.swift.expected +++ b/test/Migrator/qualified-replacement.swift.expected @@ -1,11 +1,15 @@ // REQUIRES: objc_interop -// RUN: %empty-directory(%t) && %target-swift-frontend -c -update-code -primary-file %s -F %S/mock-sdk -api-diff-data-file %S/Inputs/qualified.json -emit-migrated-file-path %t/qualified-replacement.swift.result -emit-remap-file-path %t/qualified-replacement.swift.remap -o /dev/null +// RUN: %empty-directory(%t.mod) +// RUN: %target-swift-frontend -emit-module -o %t.mod/Cities.swiftmodule %S/Inputs/Cities.swift -module-name Cities -parse-as-library +// RUN: %empty-directory(%t) && %target-swift-frontend -c -update-code -primary-file %s -F %S/mock-sdk -I %t.mod -api-diff-data-file %S/Inputs/qualified.json -emit-migrated-file-path %t/qualified-replacement.swift.result -emit-remap-file-path %t/qualified-replacement.swift.remap -o /dev/null // RUN: diff -u %S/qualified-replacement.swift.expected %t/qualified-replacement.swift.result +import Cities import Bar func foo() { _ = NewPropertyUserInterface.newFieldPlus NewPropertyUserInterface.newMethodPlus(1) _ = NewFooComparisonResult.NewFooOrderedSame let _ : FooComparisonResult = NewFooComparisonResult.NewFooOrderedSame + _ = NewCityKind.NewTown } diff --git a/test/Migrator/tuple-arguments.swift.expected b/test/Migrator/tuple-arguments.swift.expected index f4ae4e1f5a8..bf519646873 100644 --- a/test/Migrator/tuple-arguments.swift.expected +++ b/test/Migrator/tuple-arguments.swift.expected @@ -21,41 +21,41 @@ func test5(_: (Int, Int, Int) -> ()) {} test5({ (x,y,z) in }) func test6(_: ((Int, Int)) -> ()) {} -test6({ let (x,y) = $0; }) +test6({ (x,y) in }) func test7(_: ((Int, Int, Int)) -> ()) {} -test7({ let (x,y,z) = $0; }) -test6({ let (x, y) = $0; }) -test6({ let (_, _) = $0; }) -test6({ (__val:(Int, Int)) in let (x,y) = __val; }) -test6({ (__val:(Int, Int)) ->() in let (_,_) = __val; }) +test7({ (x,y,z) in }) +test6({ (_ x, _ y) in }) +test6({ (_, _) in }) +test6({ (x:Int, y:Int) in }) +test6({ (_, _) ->() in }) func test8(_: ((Int, Int)) -> Int) {} -test8 { (__val:(Int, Int)) -> Int in let (_,_) = __val; return 2 } -test8 { let (x, y) = $0; return x } +test8 { (_, _) -> Int in 2 } +test8 { (x, y) in x } func isEven(_ x: Int) -> Bool { return x % 2 == 0 } let items = Array(zip(0..<10, 0..<10)) -_ = items.filter { let (_, x) = $0; return isEven(x) } +_ = items.filter { (_, x) in isEven(x) } _ = items.filter { _ in true } func toString(indexes: Int?...) -> String { - let _ = indexes.enumerated().flatMap({ (__val:(Int, Int?)) -> String? in let (i,index) = __val; + let _ = indexes.enumerated().flatMap({ (i: Int, index: Int?) -> String? in let _: Int = i if index != nil {} return "" }) let _ = indexes.reduce(0) { print(($0, $1)); return $0 + ($1 ?? 0)} let _ = indexes.reduce(0) { (true ? ($0, $1) : (1, 2)).0 + ($1 ?? 0) } - let _ = [(1, 2)].contains { $0.0 != $0.1 } + let _ = [(1, 2)].contains { $0 != $1 } _ = ["Hello", "Foo"].sorted { print(($0, $1)); return $0.characters.count > $1.characters.count } - _ = ["Hello" : 2].map { ($0.0, ($0.1)) } + _ = ["Hello" : 2].map { ($0, ($1)) } } extension Dictionary { public mutating func merge(with dictionary: Dictionary) { - dictionary.forEach { updateValue($0.1, forKey: $0.0) } + dictionary.forEach { updateValue($1, forKey: $0) } } } let dictionary: [String: String] = [:] -_ = dictionary.first { let (column, value) = $0; return true }!.value +_ = dictionary.first { (column, value) in true }!.value diff --git a/test/Misc/expression_too_complex_3.swift b/test/Misc/expression_too_complex_3.swift index a8ea8359987..feda1276a28 100644 --- a/test/Misc/expression_too_complex_3.swift +++ b/test/Misc/expression_too_complex_3.swift @@ -1,6 +1,8 @@ // RUN: %target-typecheck-verify-swift // REQUIRES OS=macosx +// REQUIRES: rdar32796272 + // This should NOT produce an expression too complex error. var radar32680856 = [ Int32(bitPattern: 0x00), Int32(bitPattern: 0x01), Int32(bitPattern: 0x02), Int32(bitPattern: 0x03), Int32(bitPattern: 0x04), Int32(bitPattern: 0x05), Int32(bitPattern: 0x06), Int32(bitPattern: 0x07), Int32(bitPattern: 0x08), Int32(bitPattern: 0x09), Int32(bitPattern: 0x0A), Int32(bitPattern: 0x0B), Int32(bitPattern: 0x0C), Int32(bitPattern: 0x0D), Int32(bitPattern: 0x0E), Int32(bitPattern: 0x0F), diff --git a/test/Misc/expression_too_complex_4.swift b/test/Misc/expression_too_complex_4.swift new file mode 100644 index 00000000000..446149a5bb3 --- /dev/null +++ b/test/Misc/expression_too_complex_4.swift @@ -0,0 +1,6 @@ +// RUN: %target-typecheck-verify-swift -swift-version 4 -solver-expression-time-threshold=1 -warn-long-expression-type-checking=1 -solver-memory-threshold 1500000000 + +func test(_ i: Int, _ j: Int) -> Int { + return 1 + (((i >> 1) + (i >> 2) + (i >> 3) + (i >> 4) << 1) << 1) & 0x40 + // expected-error@-1 {{expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions}} +} diff --git a/test/NameBinding/Inputs/protocol-inheritance.swift b/test/NameBinding/Inputs/protocol-inheritance.swift new file mode 100644 index 00000000000..e0f8ff4c502 --- /dev/null +++ b/test/NameBinding/Inputs/protocol-inheritance.swift @@ -0,0 +1,18 @@ +public protocol Critter { + associatedtype Fur +} +public protocol Pet {} + +public typealias Cat = Critter & Pet + +public protocol Kitten : Cat {} + +extension Kitten { + public func pet() -> Fur { + while true {} + } +} + +public final class Meow : Kitten { + public typealias Fur = Purrs +} diff --git a/test/NameBinding/protocol-inheritance.swift b/test/NameBinding/protocol-inheritance.swift new file mode 100644 index 00000000000..7c5d3863974 --- /dev/null +++ b/test/NameBinding/protocol-inheritance.swift @@ -0,0 +1,5 @@ +// RUN: %target-swift-frontend -typecheck -primary-file %s %S/Inputs/protocol-inheritance.swift + +func kitty(cat: Meow) { + cat.pet() +} diff --git a/test/Parse/ConditionalCompilation/pound-if-top-level-4.swift b/test/Parse/ConditionalCompilation/pound-if-top-level-4.swift new file mode 100644 index 00000000000..c6d53e1e3d7 --- /dev/null +++ b/test/Parse/ConditionalCompilation/pound-if-top-level-4.swift @@ -0,0 +1,21 @@ +// RUN: %target-typecheck-verify-swift + +// https://bugs.swift.org/browse/SR-4426 +// '#if' in top-level code that contains only decls should not disturb forward reference. + +typealias A = B + +#if false +func foo() {} +#endif + +struct B {} + +// If '#if' contains active non-decls, we don't support forward reference. +typealias C = D // expected-error {{use of undeclared type 'D'}} + +#if true +print("ok") +#endif + +struct D {} diff --git a/test/Parse/ConditionalCompilation/stmt_in_type.swift b/test/Parse/ConditionalCompilation/stmt_in_type.swift new file mode 100644 index 00000000000..154856a648b --- /dev/null +++ b/test/Parse/ConditionalCompilation/stmt_in_type.swift @@ -0,0 +1,13 @@ +// RUN: %target-typecheck-verify-swift -D FOO + +// Test case for statements in #if block in types. + +func foo() {} + +struct S1 { // expected-note 2 {{in declaration of 'S1'}} +#if FOO + return 1; // expected-error {{expected declaration}} +#elseif BAR + foo(); // expected-error {{expected declaration}} +#endif +} diff --git a/test/Parse/ConditionalCompilation/switch_case.swift b/test/Parse/ConditionalCompilation/switch_case.swift new file mode 100644 index 00000000000..8fe0da7d65b --- /dev/null +++ b/test/Parse/ConditionalCompilation/switch_case.swift @@ -0,0 +1,221 @@ +// RUN: %target-typecheck-verify-swift -D ENABLE_C + +enum E { + case A,B +#if ENABLE_C + case C +#endif +#if ENABLE_D + case D +#endif +} + +func foo(x: E, intVal: Int) { + // Active guarded case first. + switch x { +#if ENABLE_C + case .C: + break +#endif + case .A: + break + case .B: + break + } + + // Active guarded case last. + switch x { + case .A: + break + case .B: + break +#if ENABLE_C + case .C: + break +#endif + } + + // Active guarded case middle. + switch x { + case .A: + break +#if ENABLE_C + case .C: + break +#endif + default: + break + } + + // Active guarded case after default. + switch x { + case .A: + break + default: + break +#if ENABLE_C + case .C: // expected-error {{additional 'case' blocks cannot appear after the 'default' block of a 'switch'}} + break +#endif + } + + // Inactive guarded case after default. + switch x { + case .A: + break + default: + break +#if ENABLE_D + case .D: + break +#endif + } + + // #elseif. + switch x { + case .A: + break + case .B: + break +#if NEVER +#elseif ENABLE_C + case .C: + break +#endif + } + + // #else. + switch x { + case .A: + break + case .B: + break +#if !ENABLE_C +#else + case .C: + break +#endif + } + + // Nested #if. + switch x { + case .A: + break + case .B: + break +#if ENABLE_C + #if NEVER + #else + case .C: + break + #endif +#endif + } + + // Exhaustive check. + switch x { // expected-error {{switch must be exhaustive}} expected-note {{add missing case: '.C'}} + case .A: + break + case .B: + break +#if NEVER + case .C: + break +#endif + } + + // Exhaustive check 2. + switch x { +#if ENABLE_C + case .A: + break + case .B: + break + case .C: + break +#endif + } + + // Empty check. + switch intVal { // expected-error {{'switch' statement body must have at least one 'case' or 'default' block; do you want to add a default case?}} +#if NEVER + case 1: + break + case 2: + break + case 3: + break +#endif + } + + // Non-'case' statement in '#else' block. + switch x { + case .A: + break + case .B: + break +#if ENABLE_C + case .C: + break +#else + break // expected-error {{all statements inside a switch must be covered by a 'case' or 'default'}} +#endif + } + + // Non-'case' statement in '#if' block. + switch x { // expected-error {{switch must be exhaustive}} expected-note {{add missing case: '.C'}} + case .A: + break + case .B: + break +#if !ENABLE_C + break +#else + case .C: // expected-error {{'case' label can only appear inside a 'switch' statement}} expected-error {{extraneous '.' in enum 'case' declaration}} + break +#endif + } + + // '#if ... case' after non-covered statements. + switch x { + print() // expected-error {{all statements inside a switch must be covered by a 'case' or 'default'}} +#if ENABLE_C + case .NOT_EXIST: // expected-error {{pattern cannot match values of type 'E'}} + break + case .C: + break +#endif + case .A, .B: + break + } + + // '#if ... stmt' after non-covered statements. + switch x { + print() // expected-error {{all statements inside a switch must be covered by a 'case' or 'default'}} +#if true + print() +#endif +#if ENABLE_C + case .C: + break +#endif + case .A, .B: + break + } + + // 'fallthrough' target. + switch intVal { + case 1: + fallthrough // expected-error {{'fallthrough' cannot transfer control to a case label that declares variables}} +#if ENABLE_C + case let val: + break +#endif + case 2: + fallthrough // expected-error {{'fallthrough' without a following 'case' or 'default' block}} +#if NEVER + case 3: + break +#endif + } +} diff --git a/test/Parse/ConditionalCompilation/switch_case_executable.swift b/test/Parse/ConditionalCompilation/switch_case_executable.swift new file mode 100644 index 00000000000..2500972fde4 --- /dev/null +++ b/test/Parse/ConditionalCompilation/switch_case_executable.swift @@ -0,0 +1,150 @@ +// RUN: rm -rf %t && mkdir -p %t +// RUN: %target-build-swift %s -o %t/test1 -module-name main -D PATTERN_1 +// RUN: %target-build-swift %s -o %t/test2 -module-name main -D PATTERN_2 +// RUN: %target-run %t/test1 | %FileCheck -check-prefix=CHECK -check-prefix=CHECK1 %s +// RUN: %target-run %t/test2 | %FileCheck -check-prefix=CHECK -check-prefix=CHECK2 %s + +// REQUIRES: executable_test + +//------------------------------------------------------------------------------ +print("START: switch toplevel") +// CHECK-LABEL: START: switch toplevel + +let val = 1 +switch val { + case 100: + break +#if PATTERN_1 + case 1: + print("output1") +#elseif PATTERN_2 + case 1: + print("output2") +#endif + default: + print("never") +} + +// CHECK1-NEXT: output1 +// CHECK2-NEXT: output2 + +print("END: switch toplevel") +// CHECK-NEXT: END: switch toplevel + + +//------------------------------------------------------------------------------ +print("START: switch func") +// CHECK-LABEL: START: switch func + +enum MyEnum { + case A, B +#if PATTERN_1 + case str(String) +#elseif PATTERN_2 + case int(Int) +#endif +} + +func test1(_ val: MyEnum) { + switch val { + case .A, .B: + print("never") +#if PATTERN_1 + case let .str(v): + print("output3 - " + v) +#elseif PATTERN_2 + case let .int(v): + print("output4 - \(v + 12)") +#endif + } +} + +#if PATTERN_1 +test1(.str("foo bar")) +#elseif PATTERN_2 +test1(.int(42)) +#endif +// CHECK1-NEXT: output3 - foo bar +// CHECK2-NEXT: output4 - 54 + +print("END: switch func") +// CHECK-NEXT: END: switch func + +//------------------------------------------------------------------------------ +print("START: func local") +// CHECK-LABEL: func local + +func test2(_ val: Int) -> () -> Void { + let ret: () -> Void + switch val { +#if PATTERN_1 + case let v: + struct Foo : CustomStringConvertible { + let val: Int + var description: String { return "Foo(\(val))" } + } + func fn() { + print("output5 - \(Foo(val:v))") + } + ret = fn +#elseif PATTERN_2 + case let v: + struct Bar : CustomStringConvertible { + let val: Int + var description: String { return "Bar(\(val))" } + } + ret = { print("output6 - \(Bar(val: v))") } +#endif + } + return ret +} + +test2(42)() +// CHECK1-NEXT: output5 - Foo(42) +// CHECK2-NEXT: output6 - Bar(42) + +print("END: func local") +// CHECK-NEXT: END: func local + +//------------------------------------------------------------------------------ +print("START: nested directives") +// CHECK-LABEL: START: nested directives + +#if PATTERN_1 || PATTERN_2 +func test3() { +#if PATTERN_1 || PATTERN_2 + class Nested { +#if PATTERN_1 || PATTERN_2 + func foo(_ x: Int) { + switch x { +#if true +#if PATTERN_1 + case 0..<42: + print("output7 - 0..<42 \(x)") +#elseif PATTERN_2 + case 0..<42: + print("output8 - 0..<42 \(x)") +#else + case 0..<42: + print("NEVER") +#endif + default: + print("output9 - default \(x)") +#endif + } + } +#endif + } + Nested().foo(12) +#endif + Nested().foo(53) +} +#endif +test3() +// CHECK1-NEXT: output7 - 0..<42 12 +// CHECK1-NEXT: output9 - default 53 +// CHECK2-NEXT: output8 - 0..<42 12 +// CHECK2-NEXT: output9 - default 53 + +print("END: nested directives") +// CHECK-NEXT: END: nested directives diff --git a/test/Parse/ConditionalCompilation/toplevel_parseaslibrary.swift b/test/Parse/ConditionalCompilation/toplevel_parseaslibrary.swift new file mode 100644 index 00000000000..d946620825a --- /dev/null +++ b/test/Parse/ConditionalCompilation/toplevel_parseaslibrary.swift @@ -0,0 +1,11 @@ +// RUN: %target-typecheck-verify-swift -parse-as-library -D FOO + +// '-parse-as-library' doesn't allow exprssions nor statements in #if blocks. + +func foo() {} + +#if FOO + foo() // expected-error {{expressions are not allowed at the top level}} +#else + if true { foo() } // expected-error {{statements are not allowed at the top level}} +#endif diff --git a/test/Parse/ConditionalCompilation/x64CygwinTarget.swift b/test/Parse/ConditionalCompilation/x64CygwinTarget.swift new file mode 100644 index 00000000000..0af7084f942 --- /dev/null +++ b/test/Parse/ConditionalCompilation/x64CygwinTarget.swift @@ -0,0 +1,8 @@ +// RUN: %swift -parse %s -verify -D FOO -D BAR -target x86_64-unknown-windows-cygnus -disable-objc-interop -D FOO -parse-stdlib +// RUN: %swift-ide-test -test-input-complete -source-filename=%s -target x86_64-unknown-windows-cygnus +#if arch(x86_64) && os(Cygwin) && _runtime(_Native) +class C {} +var x = C() +#endif +var y = x + diff --git a/test/Parse/ConditionalCompilation/x64WindowsTarget.swift b/test/Parse/ConditionalCompilation/x64WindowsTarget.swift index 89f0f91b683..f89314c1ad6 100644 --- a/test/Parse/ConditionalCompilation/x64WindowsTarget.swift +++ b/test/Parse/ConditionalCompilation/x64WindowsTarget.swift @@ -1,5 +1,5 @@ -// RUN: %swift -typecheck %s -verify -D FOO -D BAR -target x86_64-unknown-windows-cygnus -disable-objc-interop -D FOO -parse-stdlib -// RUN: %swift-ide-test -test-input-complete -source-filename=%s -target x86_64-unknown-windows-cygnus +// RUN: %swift -typecheck %s -verify -D FOO -D BAR -target x86_64-unknown-windows-msvc -disable-objc-interop -D FOO -parse-stdlib +// RUN: %swift-ide-test -test-input-complete -source-filename=%s -target x86_64-unknown-windows-msvc #if arch(x86_64) && os(Windows) && _runtime(_Native) && _endian(little) class C {} diff --git a/test/Parse/deprecated_where.swift b/test/Parse/deprecated_where.swift index 2eba282164f..7f3bf778e43 100644 --- a/test/Parse/deprecated_where.swift +++ b/test/Parse/deprecated_where.swift @@ -10,7 +10,7 @@ func f1(x: T) {} // 1: Inherited constraint func f2(x: T) {} // no-warning // 2: Non-trailing where -func f3(x: T) {} // expected-error {{'where' clause next to generic parameters is obsoleted}} {{10-30=}} {{37-37= where T: Womparable}} +func f3(x: T) {} // expected-error {{'where' clause next to generic parameters is obsolete}} {{10-30=}} {{37-37= where T: Womparable}} // 3: Has return type func f4(x: T) -> Int { return 2 } // no-warning // 4: Trailing where @@ -18,29 +18,29 @@ func f5(x: T) where T : Equatable {} // no-warning // FuncDecl: Choose 2 // 1,2 -func f12(x: T) {} // expected-error {{'where' clause next to generic parameters is obsoleted}} {{21-41=}} {{48-48= where T: Womparable}} +func f12(x: T) {} // expected-error {{'where' clause next to generic parameters is obsolete}} {{21-41=}} {{48-48= where T: Womparable}} // 1,3 func f13(x: T) -> Int { return 2 } // no-warning // 1,4 func f14(x: T) where T: Equatable {} // no-warning // 2,3 -func f23(x: T) -> Int { return 2 } // expected-error {{'where' clause next to generic parameters is obsoleted}} {{11-31=}} {{45-45= where T: Womparable}} +func f23(x: T) -> Int { return 2 } // expected-error {{'where' clause next to generic parameters is obsolete}} {{11-31=}} {{45-45= where T: Womparable}} // 2,4 -func f24(x: T) where T: Equatable {} // expected-error {{'where' clause next to generic parameters is obsoleted}} {{11-31=}} {{39-44=where T: Womparable,}} +func f24(x: T) where T: Equatable {} // expected-error {{'where' clause next to generic parameters is obsolete}} {{11-31=}} {{39-44=where T: Womparable,}} // 3,4 func f34(x: T) -> Int where T: Equatable { return 2 } // no-warning // FuncDecl: Choose 3 // 1,2,3 -func f123(x: T) -> Int { return 2 } // expected-error {{'where' clause next to generic parameters is obsoleted}} {{22-42=}} {{56-56= where T: Womparable}} +func f123(x: T) -> Int { return 2 } // expected-error {{'where' clause next to generic parameters is obsolete}} {{22-42=}} {{56-56= where T: Womparable}} // 1,2,4 -func f124(x: T) where T: Equatable {} // expected-error {{'where' clause next to generic parameters is obsoleted}} {{22-42=}} {{50-55=where T: Womparable,}} +func f124(x: T) where T: Equatable {} // expected-error {{'where' clause next to generic parameters is obsolete}} {{22-42=}} {{50-55=where T: Womparable,}} // 2,3,4 -func f234(x: T) -> Int where T: Equatable { return 2 } // expected-error {{'where' clause next to generic parameters is obsoleted}} {{12-32=}} {{47-52=where T: Womparable,}} +func f234(x: T) -> Int where T: Equatable { return 2 } // expected-error {{'where' clause next to generic parameters is obsolete}} {{12-32=}} {{47-52=where T: Womparable,}} // FuncDecl: Choose 4 // 1,2,3,4 -func f1234(x: T) -> Int where T: Equatable { return 2 } // expected-error {{'where' clause next to generic parameters is obsoleted}} {{23-43=}} {{58-63=where T: Womparable,}} +func f1234(x: T) -> Int where T: Equatable { return 2 } // expected-error {{'where' clause next to generic parameters is obsolete}} {{23-43=}} {{58-63=where T: Womparable,}} @@ -51,32 +51,32 @@ struct S0 {} // 1: Inherited constraint struct S1 {} // no-warning // 2: Non-trailing where -struct S2 {} // expected-error {{'where' clause next to generic parameters is obsoleted}} {{12-32=}} {{33-33= where T: Womparable}} +struct S2 {} // expected-error {{'where' clause next to generic parameters is obsolete}} {{12-32=}} {{33-33= where T: Womparable}} // 3: Trailing where struct S3 where T : Equatable {} // no-warning // NominalTypeDecl: Choose 2 // 1,2 -struct S12 {} // expected-error {{'where' clause next to generic parameters is obsoleted}} {{23-43=}} {{44-44= where T: Womparable}} +struct S12 {} // expected-error {{'where' clause next to generic parameters is obsolete}} {{23-43=}} {{44-44= where T: Womparable}} // 1,3 struct S13 where T: Equatable {} // no-warning // 2,3 -struct S23 where T: Equatable {} // expected-error {{'where' clause next to generic parameters is obsoleted}} {{13-33=}} {{35-40=where T: Womparable,}} +struct S23 where T: Equatable {} // expected-error {{'where' clause next to generic parameters is obsolete}} {{13-33=}} {{35-40=where T: Womparable,}} // NominalTypeDecl: Choose 3 // 1,2,3 -struct S123 where T: Equatable {} // expected-error {{'where' clause next to generic parameters is obsoleted}} {{24-44=}} {{46-51=where T: Womparable,}} +struct S123 where T: Equatable {} // expected-error {{'where' clause next to generic parameters is obsolete}} {{24-44=}} {{46-51=where T: Womparable,}} protocol ProtoA {} protocol ProtoB {} protocol ProtoC {} protocol ProtoD {} -func testCombinedConstraints(x: T) {} // expected-error {{'where' clause next to generic parameters is obsoleted}} {{48-64=}} {{71-71= where T: ProtoC}} -func testCombinedConstraints(x: T) where T: ProtoD {} // expected-error {{'where' clause next to generic parameters is obsoleted}} {{48-64=}} {{72-77=where T: ProtoC,}} +func testCombinedConstraints(x: T) {} // expected-error {{'where' clause next to generic parameters is obsolete}} {{48-64=}} {{71-71= where T: ProtoC}} +func testCombinedConstraints(x: T) where T: ProtoD {} // expected-error {{'where' clause next to generic parameters is obsolete}} {{48-64=}} {{72-77=where T: ProtoC,}} -func testCombinedConstraintsOld where T: ProtoC>(x: T) {} // expected-error {{'where' clause next to generic parameters is obsoleted}} {{60-76=}} {{83-83= where T: ProtoC}} +func testCombinedConstraintsOld where T: ProtoC>(x: T) {} // expected-error {{'where' clause next to generic parameters is obsolete}} {{60-76=}} {{83-83= where T: ProtoC}} // expected-warning@-1 {{'protocol<...>' composition syntax is deprecated}} -func testCombinedConstraintsOld where T: ProtoC>(x: T) where T: ProtoD {} // expected-error {{'where' clause next to generic parameters is obsoleted}} {{60-76=}} {{84-89=where T: ProtoC,}} +func testCombinedConstraintsOld where T: ProtoC>(x: T) where T: ProtoD {} // expected-error {{'where' clause next to generic parameters is obsolete}} {{60-76=}} {{84-89=where T: ProtoC,}} // expected-warning@-1 {{'protocol<...>' composition syntax is deprecated}} diff --git a/test/Parse/invalid.swift b/test/Parse/invalid.swift index 281c5cb0c3a..bf21c14fe1c 100644 --- a/test/Parse/invalid.swift +++ b/test/Parse/invalid.swift @@ -43,17 +43,6 @@ func testNotCoveredCase(x: Int) { default: break } - - switch x { // expected-error{{'switch' statement body must have at least one 'case' or 'default' block; do you want to add a default case?}} -#if true // expected-error {{all statements inside a switch must be covered by a 'case' or 'default'}} - case 1: - break - case "foobar": // ignored - break - default: - break -#endif - } } // rdar://18926814 diff --git a/test/Parse/line-directive-executable.swift b/test/Parse/line-directive-executable.swift new file mode 100644 index 00000000000..cc4e26824d2 --- /dev/null +++ b/test/Parse/line-directive-executable.swift @@ -0,0 +1,64 @@ +// RUN: %target-run-simple-swift | %FileCheck %s +// REQUIRES: executable_test + +print("START") // CHECK-LABEL: START + +func check(file: String = #file, line: Int = #line) { + print("\(file):\(line)") +} + +#sourceLocation(file: "a.swift", line: 100) +check() // CHECK-NEXT: {{^}}a.swift:100 + +public struct S { + #sourceLocation(file: "b.swift", line: 100) + func foo() { check() } + + #sourceLocation(file: "c.swift", line: 200) + + func bar() { check() } + + #sourceLocation(file: "d.swift", line: 300) +} +check() // CHECK-NEXT: {{^}}d.swift:301 +S().foo() // CHECK-NEXT: {{^}}b.swift:100 +S().bar() // CHECK-NEXT: {{^}}c.swift:201 + +enum E { +#sourceLocation(file: "e.swift", line: 400) +} +check() // CHECK-NEXT: {{^}}e.swift:401 + +class C { +#sourceLocation() +} +check() // CHECK-NEXT: .swift:[[@LINE]] + +extension C { +#sourceLocation(file: "f.swift", line: 500) + static var file: String { return #file } + + #sourceLocation(file: "g.swift", line: 600) + var line: Int { return #line } + +#sourceLocation(file: "h.swift", line: 700) +} +check() // CHECK-NEXT: {{^}}h.swift:701 +check(file: C.file, line: C().line) // CHECK-NEXT: {{^}}f.swift:600 + +func test() { +#sourceLocation(file: "i.swift", line: 800) + check() +#sourceLocation(file: "j.swift", line: 900) +} + +check() // CHECK-NEXT: {{^}}j.swift:902 +test() // CHECK-NEXT: {{^}}i.swift:800 + +#sourceLocation() +check() // CHECK-NEXT: .swift:[[@LINE]] + +#sourceLocation(file: "k.swift", line: 1000) + + +check() // CHECK-NEXT: {{^}}k.swift:1002 diff --git a/test/Parse/line-directive.swift b/test/Parse/line-directive.swift index 55a5d5bf428..8423b687a0d 100644 --- a/test/Parse/line-directive.swift +++ b/test/Parse/line-directive.swift @@ -40,3 +40,16 @@ try #sourceLocation(file: "try.swift", line: 100) LABEL: #line 200 "labeled.swift" #sourceLocation() + +class C { +#sourceLocation(file: "sr5242.swift", line: 100) + func foo() {} + let bar = 12 +#sourceLocation(file: "sr5242.swift", line: 200) +} +enum E { +#sourceLocation(file: "sr5242.swift", line: 300) + case A, B + case C, D +#sourceLocation() +} diff --git a/test/Parse/number_identifier_errors.swift b/test/Parse/number_identifier_errors.swift new file mode 100644 index 00000000000..5650c0dad98 --- /dev/null +++ b/test/Parse/number_identifier_errors.swift @@ -0,0 +1,74 @@ +// RUN: %target-typecheck-verify-swift + +// Per rdar://problem/32316666 , it is a common mistake for beginners +// to start a function name with a number, so it's worth +// special-casing the diagnostic to make it clearer. + +func 1() {} +// expected-error@-1 {{function name can only start with a letter or underscore, not a number}} +func 2.0() {} +// expected-error@-1 {{function name can only start with a letter or underscore, not a number}} +func 3func() {} +// expected-error@-1 {{function name can only start with a letter or underscore, not a number}} +// expected-error@-2 {{expected a digit after integer literal prefix}} + +protocol 4 { + // expected-error@-1 {{protocol name can only start with a letter or underscore, not a number}} + associatedtype 5 + // expected-error@-1 {{associatedtype name can only start with a letter or underscore, not a number}} +} +protocol 6.0 { + // expected-error@-1 {{protocol name can only start with a letter or underscore, not a number}} + associatedtype 7.0 + // expected-error@-1 {{associatedtype name can only start with a letter or underscore, not a number}} +} +protocol 8protocol { + // expected-error@-1 {{protocol name can only start with a letter or underscore, not a number}} + // expected-error@-2 {{expected a digit after integer literal prefix}} + associatedtype 9associatedtype + // expected-error@-1 {{associatedtype name can only start with a letter or underscore, not a number}} + // expected-error@-2 {{expected a digit after integer literal prefix}} +} + +typealias 10 = Int +// expected-error@-1 {{typealias name can only start with a letter or underscore, not a number}} +typealias 11.0 = Int +// expected-error@-1 {{typealias name can only start with a letter or underscore, not a number}} +typealias 12typealias = Int +// expected-error@-1 {{typealias name can only start with a letter or underscore, not a number}} +// expected-error@-2 {{expected a digit after integer literal prefix}} + +struct 13 {} +// expected-error@-1 {{struct name can only start with a letter or underscore, not a number}} +struct 14.0 {} +// expected-error@-1 {{struct name can only start with a letter or underscore, not a number}} +struct 15struct {} +// expected-error@-1 {{struct name can only start with a letter or underscore, not a number}} +// expected-error@-2 {{expected a digit after integer literal prefix}} + +enum 16 {} +// expected-error@-1 {{enum name can only start with a letter or underscore, not a number}} +enum 17.0 {} +// expected-error@-1 {{enum name can only start with a letter or underscore, not a number}} +enum 18enum {} +// expected-error@-1 {{enum name can only start with a letter or underscore, not a number}} +// expected-error@-2 {{expected a digit in floating point exponent}} + +class 19 { + // expected-error@-1 {{class name can only start with a letter or underscore, not a number}} + func 20() {} + // expected-error@-1 {{function name can only start with a letter or underscore, not a number}} +} +class 21.0 { + // expected-error@-1 {{class name can only start with a letter or underscore, not a number}} + func 22.0() {} + // expected-error@-1 {{function name can only start with a letter or underscore, not a number}} +} + +class 23class { + // expected-error@-1 {{class name can only start with a letter or underscore, not a number}} + // expected-error@-2 {{expected a digit after integer literal prefix}} + func 24method() {} + // expected-error@-1 {{function name can only start with a letter or underscore, not a number}} + // expected-error@-2 {{expected a digit after integer literal prefix}} +} diff --git a/test/PrintAsObjC/circularity.swift b/test/PrintAsObjC/circularity.swift index 41ac0228170..2faaca08983 100644 --- a/test/PrintAsObjC/circularity.swift +++ b/test/PrintAsObjC/circularity.swift @@ -86,9 +86,9 @@ class E2: ProtoImpl {} // CHECK-LABEL: @interface F1 : ProtoImpl class F1: ProtoImpl { } // CHECK: @end -// CHECK-LABEL @interface F2 : ProtoImpl +// CHECK-LABEL: @interface F2 : ProtoImpl // CHECK: @end -// CHECK-LABEL @interface F1 (SWIFT_EXTENSION(circularity)) +// CHECK-LABEL: @interface F1 (SWIFT_EXTENSION(circularity)) extension F1 { // CHECK: - (void)test: func test(_: NeedsProto) {} @@ -99,9 +99,9 @@ class F2: ProtoImpl {} // CHECK-LABEL: @interface G1 : ProtoImpl class G1: ProtoImpl { } // CHECK: @end -// CHECK-LABEL @protocol G2 +// CHECK-LABEL: @protocol G2 // CHECK: @end -// CHECK-LABEL @interface G1 (SWIFT_EXTENSION(circularity)) +// CHECK-LABEL: @interface G1 (SWIFT_EXTENSION(circularity)) extension G1 { // CHECK: - (void)test: func test(_: NeedsProto) {} diff --git a/test/Prototypes/BigInt.swift b/test/Prototypes/BigInt.swift index b4743671b6e..c8f0b58518d 100644 --- a/test/Prototypes/BigInt.swift +++ b/test/Prototypes/BigInt.swift @@ -121,7 +121,7 @@ public struct _BigInt : // FIXME: This is broken on 32-bit arch w/ Word = UInt64 let wordRatio = UInt.bitWidth / Word.bitWidth _sanityCheck(wordRatio != 0) - for i in 0.. () { +entry: + // CHECK: keypath $KeyPath, Optional>, (root $Optional; optional_chain : $Int; optional_wrap : $Optional) + %a = keypath $KeyPath, Optional>, (root $Optional; optional_chain : $Int; optional_wrap : $Optional) + // CHECK: keypath $KeyPath, Int>, (root $Optional; optional_force : $Int) + %b = keypath $KeyPath, Int>, (root $Optional; optional_force : $Int) + + return undef : $() +} diff --git a/test/SIL/Serialization/keypath.sil b/test/SIL/Serialization/keypath.sil index 7d550aee426..cfed287062a 100644 --- a/test/SIL/Serialization/keypath.sil +++ b/test/SIL/Serialization/keypath.sil @@ -96,12 +96,24 @@ entry: return undef : $() } +// CHECK-LABEL: sil shared @optional +sil shared @optional : $@convention(thin) () -> () { +entry: + // CHECK: keypath $KeyPath, Optional>, (root $Optional; optional_chain : $Int; optional_wrap : $Optional) + %a = keypath $KeyPath, Optional>, (root $Optional; optional_chain : $Int; optional_wrap : $Optional) + // CHECK: keypath $KeyPath, Int>, (root $Optional; optional_force : $Int) + %b = keypath $KeyPath, Int>, (root $Optional; optional_force : $Int) + + return undef : $() +} + sil @serialize_all : $@convention(thin) () -> () { entry: %0 = function_ref @stored_properties : $@convention(thin) () -> () %1 = function_ref @stored_properties_generic : $@convention(thin) () -> () %2 = function_ref @computed_properties : $@convention(thin) () -> () %3 = function_ref @computed_properties_generic : $@convention(thin) () -> () + %4 = function_ref @optional : $@convention(thin) () -> () unreachable } diff --git a/test/SIL/ownership-verifier/use_verifier.sil b/test/SIL/ownership-verifier/use_verifier.sil index 782008b5eaa..72d95b6b6f2 100644 --- a/test/SIL/ownership-verifier/use_verifier.sil +++ b/test/SIL/ownership-verifier/use_verifier.sil @@ -309,6 +309,31 @@ bb0(%0 : @owned $Optional): return %2 : $Builtin.NativeObject } +sil @access_tests : $@convention(thin) () -> () { +bb0: + %0 = alloc_box ${ var Builtin.Int64 }, var, name "x" + %1 = project_box %0 : ${ var Builtin.Int64 }, 0 + %2 = begin_access [read] [static] %1 : $*Builtin.Int64 + %3 = load [trivial] %2 : $*Builtin.Int64 + end_access %2 : $*Builtin.Int64 + destroy_value %0 : ${ var Builtin.Int64 } + + %01 = alloc_ref $RefWithInt + %011 = begin_borrow %01 : $RefWithInt + %11 = alloc_stack $Builtin.UnsafeValueBuffer + %21 = ref_element_addr %011 : $RefWithInt, #RefWithInt.value + %31 = begin_unpaired_access [modify] [dynamic] %21 : $*Builtin.Int32, %11 : $*Builtin.UnsafeValueBuffer + %41 = end_unpaired_access [dynamic] %11 : $*Builtin.UnsafeValueBuffer + %51 = begin_unpaired_access [read] [dynamic] %21 : $*Builtin.Int32, %11 : $*Builtin.UnsafeValueBuffer + %61 = end_unpaired_access [dynamic] %11 : $*Builtin.UnsafeValueBuffer + end_borrow %011 from %01 : $RefWithInt, $RefWithInt + dealloc_stack %11 : $*Builtin.UnsafeValueBuffer + destroy_value %01 : $RefWithInt + + %9999 = tuple() + return %9999 : $() +} + ////////////////////// // Terminator Tests // ////////////////////// diff --git a/test/SILGen/Inputs/struct_with_initializer.swift b/test/SILGen/Inputs/struct_with_initializer.swift index 0c3625d52bd..854fd570351 100644 --- a/test/SILGen/Inputs/struct_with_initializer.swift +++ b/test/SILGen/Inputs/struct_with_initializer.swift @@ -2,3 +2,11 @@ struct HasInitValue { var x = 10 var y: String = "" } + +struct HasPrivateInitValue { + private var x = 10 +} + +public struct PublicStructHasInitValue { + var x = 10 +} diff --git a/test/SILGen/SILDeclRef.swift b/test/SILGen/SILDeclRef.swift index 17ddcf0acc7..8c2efd10a23 100644 --- a/test/SILGen/SILDeclRef.swift +++ b/test/SILGen/SILDeclRef.swift @@ -1,5 +1,5 @@ -// RUN: %target-swift-frontend -emit-sil %s | %FileCheck %s -// RUN: %target-swift-frontend -emit-sil %s | %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all -module-name="SILDeclRef" - | %FileCheck %s +// RUN: %target-swift-frontend -emit-sil -sil-serialize-witness-tables %s | %FileCheck %s +// RUN: %target-swift-frontend -emit-sil -sil-serialize-witness-tables %s | %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all -module-name="SILDeclRef" - | %FileCheck %s // Check that all SILDeclRefs are represented in the text form with a signature. // This allows to avoid ambiguities which sometimes arise e.g. when a diff --git a/test/SILGen/addressors.swift b/test/SILGen/addressors.swift index ead711dec3b..15ef3948625 100644 --- a/test/SILGen/addressors.swift +++ b/test/SILGen/addressors.swift @@ -22,6 +22,13 @@ struct A { return base } } + + static var staticProp: Int32 { + unsafeAddress { + // Just don't trip up the verifier. + fatalError() + } + } } // CHECK-LABEL: sil hidden @_T010addressors1AV9subscripts5Int32VAFcflu : $@convention(method) (Int32, A) -> UnsafePointer diff --git a/test/SILGen/auto_closures.swift b/test/SILGen/auto_closures.swift index 5bd27027401..92e3bfb955b 100644 --- a/test/SILGen/auto_closures.swift +++ b/test/SILGen/auto_closures.swift @@ -15,7 +15,7 @@ func call_auto_closure(_ x: @autoclosure () -> Bool) -> Bool { return x() } -// CHECK-LABEL sil @_T013auto_closures05test_A21_closure_with_capture{{[_0-9a-zA-Z]*}}F +// CHECK-LABEL: sil hidden @_T013auto_closures05test_A21_closure_with_capture{{[_0-9a-zA-Z]*}}F func test_auto_closure_with_capture(_ x: Bool) -> Bool { // CHECK: [[CLOSURE:%.*]] = function_ref @_T013auto_closures05test_A21_closure_with_capture // CHECK: [[WITHCAPTURE:%.*]] = partial_apply [[CLOSURE]]( diff --git a/test/SILGen/c_function_pointers.swift b/test/SILGen/c_function_pointers.swift index 7724353fb48..18e514143f9 100644 --- a/test/SILGen/c_function_pointers.swift +++ b/test/SILGen/c_function_pointers.swift @@ -63,3 +63,9 @@ struct StructWithInitializers { init(a: ()) {} init(b: ()) {} } + +func pointers_to_nested_local_functions_in_generics(x: T) -> Int{ + func foo(y: Int) -> Int { return y } + + return calls(foo, 0) +} diff --git a/test/SILGen/dso_handle.swift b/test/SILGen/dso_handle.swift index cf8e7b46050..ae40b618b27 100644 --- a/test/SILGen/dso_handle.swift +++ b/test/SILGen/dso_handle.swift @@ -1,6 +1,6 @@ // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen %s | %FileCheck %s -// CHECK: sil_global hidden_external [[DSO:@__dso_handle]] : $Builtin.RawPointer +// CHECK: sil_global [[DSO:@__dso_handle]] : $Builtin.RawPointer // CHECK-LABEL: sil @main : $@convention(c) // CHECK: bb0 @@ -13,4 +13,12 @@ func printDSOHandle(dso: UnsafeRawPointer = #dsohandle) -> UnsafeRawPointer { return dso } +@_inlineable public func printDSOHandleInlineable(dso: UnsafeRawPointer = #dsohandle) -> UnsafeRawPointer { + return dso +} + +@_inlineable public func callsPrintDSOHandleInlineable() { + printDSOHandleInlineable() +} + _ = printDSOHandle() diff --git a/test/SILGen/extensions_multifile.swift b/test/SILGen/extensions_multifile.swift index 842caed7825..41c7c4b9d97 100644 --- a/test/SILGen/extensions_multifile.swift +++ b/test/SILGen/extensions_multifile.swift @@ -8,3 +8,15 @@ extension HasInitValue { init(z: Int) {} } + +// CHECK-LABEL: sil hidden_external [transparent] @_T020extensions_multifile19HasPrivateInitValueV1x33_0A683B047698EED319CF48214D7F519DLLSivfi : $@convention(thin) () -> Int + +extension HasPrivateInitValue { + init(z: Int) {} +} + +// CHECK-LABEL: sil hidden_external [transparent] @_T020extensions_multifile24PublicStructHasInitValueV1xSivfi : $@convention(thin) () -> Int + +extension PublicStructHasInitValue { + init(z: Int) {} +} diff --git a/test/SILGen/external-associated-type-conformance.swift b/test/SILGen/external-associated-type-conformance.swift index b05b6473569..6256f7c16ef 100644 --- a/test/SILGen/external-associated-type-conformance.swift +++ b/test/SILGen/external-associated-type-conformance.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -emit-silgen -import-objc-header %S/Inputs/external-associated-type-conformance.h %s | %FileCheck %s +// RUN: %target-swift-frontend -emit-silgen -sil-serialize-witness-tables -import-objc-header %S/Inputs/external-associated-type-conformance.h %s | %FileCheck %s // REQUIRES: objc_interop extension BadError: LocalizedError {} diff --git a/test/SILGen/guaranteed_self.swift b/test/SILGen/guaranteed_self.swift index 1b9b636c4f5..0bb5eb65814 100644 --- a/test/SILGen/guaranteed_self.swift +++ b/test/SILGen/guaranteed_self.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen %s -disable-objc-attr-requires-foundation-module | %FileCheck %s +// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen -sil-serialize-witness-tables %s -disable-objc-attr-requires-foundation-module | %FileCheck %s protocol Fooable { init() @@ -188,12 +188,16 @@ struct S: Fooable { // CHECK-NOT: destroy_addr [[SELF_ADDR]] // Witness thunk for prop3 nonmutating materializeForSet -// CHECK-LABEL: sil private [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP5prop3SifmTW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout S) -> (Builtin.RawPointer, Optional) +// CHECK-LABEL: sil private [transparent] [thunk] @_T015guaranteed_self1SVAA7FooableA2aDP5prop3SifmTW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in_guaranteed S) -> (Builtin.RawPointer, Optional) // CHECK: bb0({{.*}} [[SELF_ADDR:%.*]] : $*S): -// CHECK: [[SELF:%.*]] = load [copy] [[SELF_ADDR]] +// CHECK: [[SELF_COPY:%.*]] = alloc_stack $S +// CHECK: copy_addr [[SELF_ADDR]] to [initialization] [[SELF_COPY]] +// CHECK: [[SELF:%.*]] = load [take] [[SELF_COPY]] // CHECK: destroy_value [[SELF]] // CHECK-NOT: destroy_value [[SELF]] -// CHECK: } +// CHECK-NOT: destroy_addr [[SELF_COPY]] +// CHECK-NOT: destroy_addr [[SELF_ADDR]] +// CHECK: } // end sil function '_T015guaranteed_self1SVAA7FooableA2aDP5prop3SifmTW' // // TODO: Expected output for the other cases diff --git a/test/SILGen/indirect_enum.swift b/test/SILGen/indirect_enum.swift index b3f04cd7d71..030e77d4a24 100644 --- a/test/SILGen/indirect_enum.swift +++ b/test/SILGen/indirect_enum.swift @@ -199,18 +199,18 @@ func switchTreeA(_ x: TreeA) { // CHECK: [[TUPLE:%.*]] = load_borrow [[TUPLE_ADDR]] // CHECK: [[LEFT:%.*]] = tuple_extract [[TUPLE]] {{.*}}, 0 // CHECK: [[RIGHT:%.*]] = tuple_extract [[TUPLE]] {{.*}}, 1 + // CHECK: switch_enum [[LEFT]] : $TreeA, + // CHECK: case #TreeA.Leaf!enumelt.1: [[LEAF_CASE_LEFT:bb[0-9]+]], + // CHECK: default [[FAIL_LEFT:bb[0-9]+]] + + // CHECK: [[LEAF_CASE_LEFT]]([[LEFT_LEAF_BOX:%.*]] : $<τ_0_0> { var τ_0_0 } ): + // CHECK: [[LEFT_LEAF_VALUE:%.*]] = project_box [[LEFT_LEAF_BOX]] // CHECK: switch_enum [[RIGHT]] : $TreeA, // CHECK: case #TreeA.Leaf!enumelt.1: [[LEAF_CASE_RIGHT:bb[0-9]+]], // CHECK: default [[FAIL_RIGHT:bb[0-9]+]] // CHECK: [[LEAF_CASE_RIGHT]]([[RIGHT_LEAF_BOX:%.*]] : $<τ_0_0> { var τ_0_0 } ): // CHECK: [[RIGHT_LEAF_VALUE:%.*]] = project_box [[RIGHT_LEAF_BOX]] - // CHECK: switch_enum [[LEFT]] : $TreeA, - // CHECK: case #TreeA.Leaf!enumelt.1: [[LEAF_CASE_LEFT:bb[0-9]+]], - // CHECK: default [[FAIL_LEFT:bb[0-9]+]] - - // CHECK: [[LEAF_CASE_LEFT]]([[LEFT_LEAF_BOX:%.*]] : $<τ_0_0> { var τ_0_0 } ): - // CHECK: [[LEFT_LEAF_VALUE:%.*]] = project_box [[LEFT_LEAF_BOX]] // CHECK: copy_addr [[LEFT_LEAF_VALUE]] // CHECK: copy_addr [[RIGHT_LEAF_VALUE]] // -- x +1 @@ -218,10 +218,10 @@ func switchTreeA(_ x: TreeA) { // CHECK: end_borrow [[BORROWED_ARG]] from [[ARG]] // CHECK: br [[OUTER_CONT]] - // CHECK: [[FAIL_LEFT]]: + // CHECK: [[FAIL_RIGHT]]: // CHECK: br [[DEFAULT:bb[0-9]+]] - // CHECK: [[FAIL_RIGHT]]: + // CHECK: [[FAIL_LEFT]]: // CHECK: br [[DEFAULT]] case .Branch(.Leaf(let x), .Leaf(let y)): @@ -278,16 +278,16 @@ func switchTreeB(_ x: TreeB) { // CHECK: [[TUPLE:%.*]] = project_box [[BOX]] // CHECK: [[LEFT:%.*]] = tuple_element_addr [[TUPLE]] // CHECK: [[RIGHT:%.*]] = tuple_element_addr [[TUPLE]] - // CHECK: switch_enum_addr [[RIGHT]] {{.*}}, default [[RIGHT_FAIL:bb[0-9]+]] - - // CHECK: bb{{.*}}: - // CHECK: copy_addr [[RIGHT]] to [initialization] [[RIGHT_COPY:%.*]] : - // CHECK: [[RIGHT_LEAF:%.*]] = unchecked_take_enum_data_addr [[RIGHT_COPY]] : $*TreeB, #TreeB.Leaf // CHECK: switch_enum_addr [[LEFT]] {{.*}}, default [[LEFT_FAIL:bb[0-9]+]] // CHECK: bb{{.*}}: // CHECK: copy_addr [[LEFT]] to [initialization] [[LEFT_COPY:%.*]] : // CHECK: [[LEFT_LEAF:%.*]] = unchecked_take_enum_data_addr [[LEFT_COPY]] : $*TreeB, #TreeB.Leaf + // CHECK: switch_enum_addr [[RIGHT]] {{.*}}, default [[RIGHT_FAIL:bb[0-9]+]] + + // CHECK: bb{{.*}}: + // CHECK: copy_addr [[RIGHT]] to [initialization] [[RIGHT_COPY:%.*]] : + // CHECK: [[RIGHT_LEAF:%.*]] = unchecked_take_enum_data_addr [[RIGHT_COPY]] : $*TreeB, #TreeB.Leaf // CHECK: copy_addr [take] [[LEFT_LEAF]] to [initialization] [[X:%.*]] : // CHECK: copy_addr [take] [[RIGHT_LEAF]] to [initialization] [[Y:%.*]] : // CHECK: function_ref @_T013indirect_enum1c{{[_0-9a-zA-Z]*}}F @@ -295,10 +295,10 @@ func switchTreeB(_ x: TreeB) { // CHECK: dealloc_stack [[Y]] // CHECK: destroy_addr [[X]] // CHECK: dealloc_stack [[X]] - // CHECK-NOT: destroy_addr [[LEFT_COPY]] - // CHECK: dealloc_stack [[LEFT_COPY]] // CHECK-NOT: destroy_addr [[RIGHT_COPY]] // CHECK: dealloc_stack [[RIGHT_COPY]] + // CHECK-NOT: destroy_addr [[LEFT_COPY]] + // CHECK: dealloc_stack [[LEFT_COPY]] // -- box +0 // CHECK: destroy_value [[BOX]] // CHECK-NOT: destroy_addr [[TREE_COPY]] @@ -308,16 +308,16 @@ func switchTreeB(_ x: TreeB) { case .Branch(.Leaf(let x), .Leaf(let y)): c(x, y) - // CHECK: [[LEFT_FAIL]]: - // CHECK: destroy_addr [[RIGHT_LEAF]] - // CHECK-NOT: destroy_addr [[RIGHT_COPY]] - // CHECK: dealloc_stack [[RIGHT_COPY]] + // CHECK: [[RIGHT_FAIL]]: + // CHECK: destroy_addr [[LEFT_LEAF]] + // CHECK-NOT: destroy_addr [[LEFT_COPY]] + // CHECK: dealloc_stack [[LEFT_COPY]] // CHECK: destroy_value [[BOX]] // CHECK-NOT: destroy_addr [[TREE_COPY]] // CHECK: dealloc_stack [[TREE_COPY]] // CHECK: br [[INNER_CONT:bb[0-9]+]] - // CHECK: [[RIGHT_FAIL]]: + // CHECK: [[LEFT_FAIL]]: // CHECK: destroy_value [[BOX]] // CHECK-NOT: destroy_addr [[TREE_COPY]] // CHECK: dealloc_stack [[TREE_COPY]] diff --git a/test/SILGen/initializers.swift b/test/SILGen/initializers.swift index 6493576e914..afdbb20d241 100644 --- a/test/SILGen/initializers.swift +++ b/test/SILGen/initializers.swift @@ -556,6 +556,8 @@ class ThrowBaseClass { required init(throwingCanary: Canary) throws {} init(canary: Canary) {} init(noFail: ()) {} + init(fail: Int) throws {} + init(noFail: Int) {} } class ThrowDerivedClass : ThrowBaseClass { @@ -572,59 +574,308 @@ class ThrowDerivedClass : ThrowBaseClass { try! super.init() } - init(fail: Int) {} + override init(fail: Int) throws {} + override init(noFail: Int) {} - init(failBeforeFullInitialization: Int) throws { - try unwrap(failBeforeFullInitialization) + // ---- Delegating to super + + // CHECK-LABEL: sil hidden @_T021failable_initializers17ThrowDerivedClassCACSi30delegatingFailBeforeDelegation_tKcfc : $@convention(method) (Int, @owned ThrowDerivedClass) -> (@owned ThrowDerivedClass, @error Error) { + // CHECK: bb0( + // First initialize. + // CHECK: [[REF:%.*]] = alloc_box ${ var ThrowDerivedClass }, let, name "self" + // CHECK: [[MARK_UNINIT:%.*]] = mark_uninitialized [derivedself] [[REF]] : ${ var ThrowDerivedClass } + // CHECK: [[PROJ:%.*]] = project_box [[MARK_UNINIT]] + // CHECK: store {{%.*}} to [init] [[PROJ]] + // + // Then initialize the canary with nil. We are able to borrow the initialized self to avoid retain/release overhead. + // CHECK: [[CANARY_FUNC:%.*]] = function_ref @_T021failable_initializers17ThrowDerivedClassC6canaryAA6CanaryCSgvfi : + // CHECK: [[OPT_CANARY:%.*]] = apply [[CANARY_FUNC]]() + // CHECK: [[SELF:%.*]] = load_borrow [[PROJ]] + // CHECK: [[CANARY_ADDR:%.*]] = ref_element_addr [[SELF]] + // CHECK: [[CANARY_ACCESS:%.*]] = begin_access [modify] [dynamic] [[CANARY_ADDR]] + // CHECK: assign [[OPT_CANARY]] to [[CANARY_ACCESS]] + // CHECK: end_access [[CANARY_ACCESS]] + // CHECK: end_borrow [[SELF]] from [[PROJ]] + // + // Now we perform the unwrap. + // CHECK: [[UNWRAP_FN:%.*]] = function_ref @_T021failable_initializers6unwrapS2iKF : $@convention(thin) + // CHECK: try_apply [[UNWRAP_FN]]({{%.*}}) : $@convention(thin) (Int) -> (Int, @error Error), normal [[NORMAL_BB:bb[0-9]+]], error [[ERROR_BB:bb[0-9]+]] + // + // CHECK: [[NORMAL_BB]]( + // CHECK: [[SELF:%.*]] = load [take] [[PROJ]] + // CHECK: [[SELF_BASE:%.*]] = upcast [[SELF]] : $ThrowDerivedClass to $ThrowBaseClass + // CHECK: [[BASE_INIT_FN:%.*]] = function_ref @_T021failable_initializers14ThrowBaseClassCACyt6noFail_tcfc : $@convention(method) + // CHECK: [[SELF_INIT_BASE:%.*]] = apply [[BASE_INIT_FN]]([[SELF_BASE]]) + // CHECK: [[SELF:%.*]] = unchecked_ref_cast [[SELF_INIT_BASE]] : $ThrowBaseClass to $ThrowDerivedClass + // CHECK: store [[SELF]] to [init] [[PROJ]] + // CHECK: [[SELF:%.*]] = load [copy] [[PROJ]] + // CHECK: destroy_value [[MARK_UNINIT]] + // CHECK: return [[SELF]] + // + // Finally the error BB. We do not touch self since self is still in the + // box implying that destroying MARK_UNINIT will destroy it for us. + // CHECK: [[ERROR_BB]]([[ERROR:%.*]] : $Error): + // CHECK: destroy_value [[MARK_UNINIT]] + // CHECK: throw [[ERROR]] + // CHECK: } // end sil function '_T021failable_initializers17ThrowDerivedClassCACSi30delegatingFailBeforeDelegation_tKcfc' + init(delegatingFailBeforeDelegation : Int) throws { + try unwrap(delegatingFailBeforeDelegation) super.init(noFail: ()) } - init(failBeforeFullInitialization: Int, failDuringFullInitialization: Int) throws { - try unwrap(failBeforeFullInitialization) + // CHECK-LABEL: sil hidden @_T021failable_initializers17ThrowDerivedClassCACSi41delegatingFailDuringDelegationArgEmission_tKcfc : $@convention(method) (Int, @owned ThrowDerivedClass) -> (@owned ThrowDerivedClass, @error Error) { + // CHECK: bb0( + // First initialize. + // CHECK: [[REF:%.*]] = alloc_box ${ var ThrowDerivedClass }, let, name "self" + // CHECK: [[MARK_UNINIT:%.*]] = mark_uninitialized [derivedself] [[REF]] : ${ var ThrowDerivedClass } + // CHECK: [[PROJ:%.*]] = project_box [[MARK_UNINIT]] + // CHECK: store {{%.*}} to [init] [[PROJ]] + // + // Then initialize the canary with nil. We are able to borrow the initialized self to avoid retain/release overhead. + // CHECK: [[CANARY_FUNC:%.*]] = function_ref @_T021failable_initializers17ThrowDerivedClassC6canaryAA6CanaryCSgvfi : + // CHECK: [[OPT_CANARY:%.*]] = apply [[CANARY_FUNC]]() + // CHECK: [[SELF:%.*]] = load_borrow [[PROJ]] + // CHECK: [[CANARY_ADDR:%.*]] = ref_element_addr [[SELF]] + // CHECK: [[CANARY_ACCESS:%.*]] = begin_access [modify] [dynamic] [[CANARY_ADDR]] + // CHECK: assign [[OPT_CANARY]] to [[CANARY_ACCESS]] + // CHECK: end_access [[CANARY_ACCESS]] + // CHECK: end_borrow [[SELF]] from [[PROJ]] + // + // Now we begin argument emission where we perform the unwrap. + // CHECK: [[SELF:%.*]] = load [take] [[PROJ]] + // CHECK: [[BASE_SELF:%.*]] = upcast [[SELF]] : $ThrowDerivedClass to $ThrowBaseClass + // CHECK: [[INIT_FN:%.*]] = function_ref @_T021failable_initializers14ThrowBaseClassCACSi6noFail_tcfc : $@convention(method) + // CHECK: [[UNWRAP_FN:%.*]] = function_ref @_T021failable_initializers6unwrapS2iKF : $@convention(thin) + // CHECK: try_apply [[UNWRAP_FN]]({{%.*}}) : $@convention(thin) (Int) -> (Int, @error Error), normal [[NORMAL_BB:bb[0-9]+]], error [[ERROR_BB:bb[0-9]+]] + // + // Now we emit the call to the initializer. Notice how we return self back to + // its memory locatio nbefore any other work is done. + // CHECK: [[NORMAL_BB]]( + // CHECK: [[BASE_SELF_INIT:%.*]] = apply [[INIT_FN]]({{%.*}}, [[BASE_SELF]]) + // CHECK: [[SELF:%.*]] = unchecked_ref_cast [[BASE_SELF_INIT]] : $ThrowBaseClass to $ThrowDerivedClass + // CHECK: store [[SELF]] to [init] [[PROJ]] + // + // Handle the return value. + // CHECK: [[SELF:%.*]] = load [copy] [[PROJ]] + // CHECK: destroy_value [[MARK_UNINIT]] + // CHECK: return [[SELF]] + // + // When the error is thrown, we need to: + // 1. Store self back into the "conceptually" uninitialized box. + // 2. destroy the box. + // 3. Perform the rethrow. + // CHECK: [[ERROR_BB]]([[ERROR:%.*]] : $Error): + // CHECK: [[SELF:%.*]] = unchecked_ref_cast [[BASE_SELF]] : $ThrowBaseClass to $ThrowDerivedClass + // CHECK: store [[SELF]] to [init] [[PROJ]] + // CHECK: destroy_value [[MARK_UNINIT]] + // CHECK: throw [[ERROR]] + // CHECK: } // end sil function '_T021failable_initializers17ThrowDerivedClassCACSi41delegatingFailDuringDelegationArgEmission_tKcfc' + init(delegatingFailDuringDelegationArgEmission : Int) throws { + super.init(noFail: try unwrap(delegatingFailDuringDelegationArgEmission)) + } + + // CHECK-LABEL: sil hidden @_T021failable_initializers17ThrowDerivedClassCACSi34delegatingFailDuringDelegationCall_tKcfc : $@convention(method) (Int, @owned ThrowDerivedClass) -> (@owned ThrowDerivedClass, @error Error) { + // CHECK: bb0( + // First initialize. + // CHECK: [[REF:%.*]] = alloc_box ${ var ThrowDerivedClass }, let, name "self" + // CHECK: [[MARK_UNINIT:%.*]] = mark_uninitialized [derivedself] [[REF]] : ${ var ThrowDerivedClass } + // CHECK: [[PROJ:%.*]] = project_box [[MARK_UNINIT]] + // CHECK: store {{%.*}} to [init] [[PROJ]] + // + // Call the initializer. + // CHECK: [[SELF:%.*]] = load [take] [[PROJ]] + // CHECK: [[BASE_SELF:%.*]] = upcast [[SELF]] : $ThrowDerivedClass to $ThrowBaseClass + // CHECK: [[INIT_FN:%.*]] = function_ref @_T021failable_initializers14ThrowBaseClassCACyKcfc : $@convention(method) + // CHECK: try_apply [[INIT_FN]]([[BASE_SELF]]) : $@convention(method) (@owned ThrowBaseClass) -> (@owned ThrowBaseClass, @error Error), normal [[NORMAL_BB:bb[0-9]+]], error [[ERROR_BB:bb[0-9]+]] + // + // Insert the return statement into the normal block... + // CHECK: [[NORMAL_BB]]([[BASE_SELF_INIT:%.*]] : $ThrowBaseClass): + // CHECK: [[OUT_SELF:%.*]] = unchecked_ref_cast [[BASE_SELF_INIT]] : $ThrowBaseClass to $ThrowDerivedClass + // CHECK: store [[OUT_SELF]] to [init] [[PROJ]] + // CHECK: [[RESULT:%.*]] = load [copy] [[PROJ]] + // CHECK: destroy_value [[MARK_UNINIT]] + // CHECK: return [[RESULT]] + // + // ... and destroy the box in the error block. + // CHECK: [[ERROR_BB]]([[ERROR:%.*]] : $Error): + // CHECK-NEXT: destroy_value [[MARK_UNINIT]] + // CHECK-NEXT: throw [[ERROR]] + // CHECK: } // end sil function '_T021failable_initializers17ThrowDerivedClassCACSi34delegatingFailDuringDelegationCall_tKcfc' + init(delegatingFailDuringDelegationCall : Int) throws { try super.init() } - init(failAfterFullInitialization: Int) throws { + // CHECK-LABEL: sil hidden @_T021failable_initializers17ThrowDerivedClassCACSi29delegatingFailAfterDelegation_tKcfc : $@convention(method) (Int, @owned ThrowDerivedClass) -> (@owned ThrowDerivedClass, @error Error) { + // CHECK: bb0( + // First initialize. + // CHECK: [[REF:%.*]] = alloc_box ${ var ThrowDerivedClass }, let, name "self" + // CHECK: [[MARK_UNINIT:%.*]] = mark_uninitialized [derivedself] [[REF]] : ${ var ThrowDerivedClass } + // CHECK: [[PROJ:%.*]] = project_box [[MARK_UNINIT]] + // CHECK: store {{%.*}} to [init] [[PROJ]] + // + // Call the initializer and then store the new self back into its memory slot. + // CHECK: [[SELF:%.*]] = load [take] [[PROJ]] + // CHECK: [[BASE_SELF:%.*]] = upcast [[SELF]] : $ThrowDerivedClass to $ThrowBaseClass + // CHECK: [[INIT_FN:%.*]] = function_ref @_T021failable_initializers14ThrowBaseClassCACyt6noFail_tcfc : $@convention(method) + // CHECK: [[NEW_SELF:%.*]] = apply [[INIT_FN]]([[BASE_SELF]]) : $@convention(method) (@owned ThrowBaseClass) -> @owned ThrowBaseClass + // CHECK: [[NEW_SELF_CAST:%.*]] = unchecked_ref_cast [[NEW_SELF]] : $ThrowBaseClass to $ThrowDerivedClass + // CHECK: store [[NEW_SELF_CAST]] to [init] [[PROJ]] + // + // Finally perform the unwrap. + // CHECK: [[UNWRAP_FN:%.*]] = function_ref @_T021failable_initializers6unwrapS2iKF : $@convention(thin) (Int) -> (Int, @error Error) + // CHECK: try_apply [[UNWRAP_FN]]({{%.*}}) : $@convention(thin) (Int) -> (Int, @error Error), normal [[NORMAL_BB:bb[0-9]+]], error [[ERROR_BB:bb[0-9]+]] + // + // Insert the return statement into the normal block... + // CHECK: [[NORMAL_BB]]( + // CHECK: [[RESULT:%.*]] = load [copy] [[PROJ]] + // CHECK: destroy_value [[MARK_UNINIT]] + // CHECK: return [[RESULT]] + // + // ... and destroy the box in the error block. + // CHECK: [[ERROR_BB]]([[ERROR:%.*]] : $Error): + // CHECK-NEXT: destroy_value [[MARK_UNINIT]] + // CHECK-NEXT: throw [[ERROR]] + // CHECK: } // end sil function '_T021failable_initializers17ThrowDerivedClassCACSi29delegatingFailAfterDelegation_tKcfc' + init(delegatingFailAfterDelegation : Int) throws { super.init(noFail: ()) - try unwrap(failAfterFullInitialization) + try unwrap(delegatingFailAfterDelegation) } - init(failAfterFullInitialization: Int, failDuringFullInitialization: Int) throws { + // CHECK-LABEL: sil hidden @_T021failable_initializers17ThrowDerivedClassCACSi30delegatingFailBeforeDelegation_Si0fg6DuringI11ArgEmissiontKcfc : $@convention(method) (Int, Int, @owned ThrowDerivedClass) -> (@owned ThrowDerivedClass, @error Error) { + // Create our box. + // CHECK: [[REF:%.*]] = alloc_box ${ var ThrowDerivedClass }, let, name "self" + // CHECK: [[MARK_UNINIT:%.*]] = mark_uninitialized [derivedself] [[REF]] : ${ var ThrowDerivedClass } + // CHECK: [[PROJ:%.*]] = project_box [[MARK_UNINIT]] + // + // Perform the unwrap. + // CHECK: [[UNWRAP_FN:%.*]] = function_ref @_T021failable_initializers6unwrapS2iKF : $@convention(thin) (Int) -> (Int, @error Error) + // CHECK: try_apply [[UNWRAP_FN]]({{%.*}}) : $@convention(thin) (Int) -> (Int, @error Error), normal [[UNWRAP_NORMAL_BB:bb[0-9]+]], error [[UNWRAP_ERROR_BB:bb[0-9]+]] + // + // Now we begin argument emission where we perform another unwrap. + // CHECK: [[UNWRAP_NORMAL_BB]]( + // CHECK: [[SELF:%.*]] = load [take] [[PROJ]] + // CHECK: [[SELF_CAST:%.*]] = upcast [[SELF]] : $ThrowDerivedClass to $ThrowBaseClass + // CHECK: [[INIT_FN2:%.*]] = function_ref @_T021failable_initializers14ThrowBaseClassCACSi6noFail_tcfc : $@convention(method) (Int, @owned ThrowBaseClass) -> @owned ThrowBaseClass + // CHECK: [[UNWRAP_FN2:%.*]] = function_ref @_T021failable_initializers6unwrapS2iKF : $@convention(thin) (Int) -> (Int, @error Error) + // CHECK: try_apply [[UNWRAP_FN2]]({{%.*}}) : $@convention(thin) (Int) -> (Int, @error Error), normal [[UNWRAP_NORMAL_BB2:bb[0-9]+]], error [[UNWRAP_ERROR_BB2:bb[0-9]+]] + // + // Then since this example has a + // CHECK: [[UNWRAP_NORMAL_BB2]]([[INT:%.*]] : $Int): + // CHECK: [[NEW_SELF_CAST:%.*]] = apply [[INIT_FN2]]([[INT]], [[SELF_CAST]]) : $@convention(method) (Int, @owned ThrowBaseClass) -> @owned ThrowBaseClass + // CHECK: [[NEW_SELF:%.*]] = unchecked_ref_cast [[NEW_SELF_CAST]] : $ThrowBaseClass to $ThrowDerivedClass + // CHECK: store [[NEW_SELF]] to [init] [[PROJ]] + // CHECK: [[RESULT:%.*]] = load [copy] [[PROJ]] + // CHECK: destroy_value [[MARK_UNINIT]] + // CHECK: return [[RESULT]] + // + // ... and destroy the box in the error block. + // CHECK: [[UNWRAP_ERROR_BB]]([[ERROR:%.*]] : $Error): + // CHECK: br [[ERROR_JOIN:bb[0-9]+]]([[ERROR]] + // + // CHECK: [[UNWRAP_ERROR_BB2]]([[ERROR:%.*]] : $Error): + // CHECK: [[SELF_CASTED_BACK:%.*]] = unchecked_ref_cast [[SELF_CAST]] : $ThrowBaseClass to $ThrowDerivedClass + // CHECK: store [[SELF_CASTED_BACK]] to [init] [[PROJ]] + // CHECK: br [[ERROR_JOIN]]([[ERROR]] + // + // CHECK: [[ERROR_JOIN]]([[ERROR_PHI:%.*]] : $Error): + // CHECK: destroy_value [[MARK_UNINIT]] + // CHECK: throw [[ERROR_PHI]] + // CHECK: } // end sil function '_T021failable_initializers17ThrowDerivedClassCACSi30delegatingFailBeforeDelegation_Si0fg6DuringI11ArgEmissiontKcfc' + init(delegatingFailBeforeDelegation : Int, delegatingFailDuringDelegationArgEmission : Int) throws { + try unwrap(delegatingFailBeforeDelegation) + super.init(noFail: try unwrap(delegatingFailDuringDelegationArgEmission)) + } + + init(delegatingFailBeforeDelegation : Int, delegatingFailDuringDelegationCall : Int) throws { + try unwrap(delegatingFailBeforeDelegation) try super.init() - try unwrap(failAfterFullInitialization) } - init(failBeforeFullInitialization: Int, failAfterFullInitialization: Int) throws { - try unwrap(failBeforeFullInitialization) + init(delegatingFailBeforeDelegation : Int, delegatingFailAfterDelegation : Int) throws { + try unwrap(delegatingFailBeforeDelegation) super.init(noFail: ()) - try unwrap(failAfterFullInitialization) + try unwrap(delegatingFailAfterDelegation) } - init(failBeforeFullInitialization: Int, failDuringFullInitialization: Int, failAfterFullInitialization: Int) throws { - try unwrap(failBeforeFullInitialization) + init(delegatingFailDuringDelegationArgEmission : Int, delegatingFailDuringDelegationCall : Int) throws { + try super.init(fail: try unwrap(delegatingFailDuringDelegationArgEmission)) + } + + init(delegatingFailDuringDelegationArgEmission : Int, delegatingFailAfterDelegation : Int) throws { + super.init(noFail: try unwrap(delegatingFailDuringDelegationArgEmission)) + try unwrap(delegatingFailAfterDelegation) + } + + init(delegatingFailDuringDelegationCall : Int, delegatingFailAfterDelegation : Int) throws { try super.init() - try unwrap(failAfterFullInitialization) + try unwrap(delegatingFailAfterDelegation) } - convenience init(noFail2: ()) { - try! self.init() + init(delegatingFailBeforeDelegation : Int, delegatingFailDuringDelegationArgEmission : Int, delegatingFailDuringDelegationCall : Int) throws { + try unwrap(delegatingFailBeforeDelegation) + try super.init(fail: try unwrap(delegatingFailDuringDelegationArgEmission)) } - convenience init(failBeforeDelegation: Int) throws { - try unwrap(failBeforeDelegation) + init(delegatingFailBeforeDelegation : Int, delegatingFailDuringDelegationArgEmission : Int, delegatingFailAfterDelegation : Int) throws { + try unwrap(delegatingFailBeforeDelegation) + super.init(noFail: try unwrap(delegatingFailDuringDelegationArgEmission)) + try unwrap(delegatingFailAfterDelegation) + } + + init(delegatingFailBeforeDelegation : Int, delegatingFailDuringDelegationCall : Int, delegatingFailAfterDelegation : Int) throws { + try unwrap(delegatingFailBeforeDelegation) + try super.init() + try unwrap(delegatingFailAfterDelegation) + } + + init(delegatingFailDuringDelegationArgEmission : Int, delegatingFailDuringDelegationCall : Int, delegatingFailAfterDelegation : Int) throws { + try super.init(fail: try unwrap(delegatingFailDuringDelegationArgEmission)) + try unwrap(delegatingFailAfterDelegation) + } + + init(delegatingFailBeforeDelegation : Int, delegatingFailDuringDelegationArgEmission : Int, delegatingFailDuringDelegationCall : Int, delegatingFailAfterDelegation : Int) throws { + try unwrap(delegatingFailBeforeDelegation) + try super.init(fail: try unwrap(delegatingFailDuringDelegationArgEmission)) + try unwrap(delegatingFailAfterDelegation) + } + + // ---- Delegating to other self method. + + convenience init(chainingFailBeforeDelegation : Int) throws { + try unwrap(chainingFailBeforeDelegation) self.init(noFail: ()) } - convenience init(failDuringDelegation: Int) throws { + convenience init(chainingFailDuringDelegationArgEmission : Int) throws { + self.init(noFail: try unwrap(chainingFailDuringDelegationArgEmission)) + } + + convenience init(chainingFailDuringDelegationCall : Int) throws { try self.init() } - convenience init(failBeforeOrDuringDelegation: Int) throws { - try unwrap(failBeforeOrDuringDelegation) + convenience init(chainingFailAfterDelegation : Int) throws { + self.init(noFail: ()) + try unwrap(chainingFailAfterDelegation) + } + + convenience init(chainingFailBeforeDelegation : Int, chainingFailDuringDelegationArgEmission : Int) throws { + try unwrap(chainingFailBeforeDelegation) + self.init(noFail: try unwrap(chainingFailDuringDelegationArgEmission)) + } + + convenience init(chainingFailBeforeDelegation : Int, chainingFailDuringDelegationCall : Int) throws { + try unwrap(chainingFailBeforeDelegation) try self.init() } - // CHECK-LABEL: sil hidden @_T021failable_initializers17ThrowDerivedClassCACSi29failBeforeOrDuringDelegation2_tKcfc + convenience init(chainingFailBeforeDelegation : Int, chainingFailAfterDelegation : Int) throws { + try unwrap(chainingFailBeforeDelegation) + self.init(noFail: ()) + try unwrap(chainingFailAfterDelegation) + } + + // CHECK-LABEL: sil hidden @_T021failable_initializers17ThrowDerivedClassCACSi39chainingFailDuringDelegationArgEmission_Si0fghI4CalltKcfc : $@convention(method) (Int, Int, @owned ThrowDerivedClass) -> (@owned ThrowDerivedClass, @error Error) { // CHECK: bb0({{.*}}, [[OLD_SELF:%.*]] : $ThrowDerivedClass): // CHECK: [[SELF_BOX:%.*]] = alloc_box ${ var ThrowDerivedClass }, let, name "self" // CHECK: [[MARKED_SELF_BOX:%.*]] = mark_uninitialized [delegatingself] [[SELF_BOX]] @@ -652,16 +903,16 @@ class ThrowDerivedClass : ThrowBaseClass { // CHECK: [[THROWING_BB]]([[ERROR:%.*]] : $Error): // CHECK-NEXT: destroy_value [[MARKED_SELF_BOX]] // CHECK-NEXT: throw [[ERROR]] - convenience init(failBeforeOrDuringDelegation2: Int) throws { - try self.init(failBeforeDelegation: unwrap(failBeforeOrDuringDelegation2)) + convenience init(chainingFailDuringDelegationArgEmission : Int, chainingFailDuringDelegationCall : Int) throws { + try self.init(fail: try unwrap(chainingFailDuringDelegationArgEmission)) } - convenience init(failAfterDelegation: Int) throws { - self.init(noFail: ()) - try unwrap(failAfterDelegation) + convenience init(chainingFailDuringDelegationArgEmission : Int, chainingFailAfterDelegation : Int) throws { + self.init(noFail: try unwrap(chainingFailDuringDelegationArgEmission)) + try unwrap(chainingFailAfterDelegation) } - // CHECK-LABEL: sil hidden @_T021failable_initializers17ThrowDerivedClassCACSi27failDuringOrAfterDelegation_tKcfc : $@convention(method) (Int, @owned ThrowDerivedClass) -> (@owned ThrowDerivedClass, @error Error) { + // CHECK-LABEL: sil hidden @_T021failable_initializers17ThrowDerivedClassCACSi32chainingFailDuringDelegationCall_Si0fg5AfterI0tKcfc : $@convention(method) (Int, Int, @owned ThrowDerivedClass) -> (@owned ThrowDerivedClass, @error Error) { // CHECK: bb0({{.*}}, [[OLD_SELF:%.*]] : $ThrowDerivedClass): // CHECK: [[SELF_BOX:%.*]] = alloc_box ${ var ThrowDerivedClass }, let, name "self" // CHECK: [[MARKED_SELF_BOX:%.*]] = mark_uninitialized [delegatingself] [[SELF_BOX]] @@ -690,15 +941,38 @@ class ThrowDerivedClass : ThrowBaseClass { // CHECK: [[THROWING_BB]]([[ERROR:%.*]] : $Error): // CHECK-NEXT: destroy_value [[MARKED_SELF_BOX]] // CHECK-NEXT: throw [[ERROR]] - convenience init(failDuringOrAfterDelegation: Int) throws { + // CHECK: } // end sil function '_T021failable_initializers17ThrowDerivedClassCACSi28chainingFailBeforeDelegation_Si0fg6DuringI11ArgEmissionSi0fgjI4CalltKcfC' + convenience init(chainingFailDuringDelegationCall : Int, chainingFailAfterDelegation : Int) throws { try self.init() - try unwrap(failDuringOrAfterDelegation) + try unwrap(chainingFailAfterDelegation) } - convenience init(failBeforeOrAfterDelegation: Int) throws { - try unwrap(failBeforeOrAfterDelegation) - self.init(noFail: ()) - try unwrap(failBeforeOrAfterDelegation) + convenience init(chainingFailBeforeDelegation : Int, chainingFailDuringDelegationArgEmission : Int, chainingFailDuringDelegationCall : Int) throws { + try unwrap(chainingFailBeforeDelegation) + try self.init(fail: try unwrap(chainingFailDuringDelegationArgEmission)) + } + + convenience init(chainingFailBeforeDelegation : Int, chainingFailDuringDelegationArgEmission : Int, chainingFailAfterDelegation : Int) throws { + try unwrap(chainingFailBeforeDelegation) + self.init(noFail: try unwrap(chainingFailDuringDelegationArgEmission)) + try unwrap(chainingFailAfterDelegation) + } + + convenience init(chainingFailBeforeDelegation : Int, chainingFailDuringDelegationCall : Int, chainingFailAfterDelegation : Int) throws { + try unwrap(chainingFailBeforeDelegation) + try self.init() + try unwrap(chainingFailAfterDelegation) + } + + convenience init(chainingFailDuringDelegationArgEmission : Int, chainingFailDuringDelegationCall : Int, chainingFailAfterDelegation : Int) throws { + try self.init(fail: try unwrap(chainingFailDuringDelegationArgEmission)) + try unwrap(chainingFailAfterDelegation) + } + + convenience init(chainingFailBeforeDelegation : Int, chainingFailDuringDelegationArgEmission : Int, chainingFailDuringDelegationCall : Int, chainingFailAfterDelegation : Int) throws { + try unwrap(chainingFailBeforeDelegation) + try self.init(fail: try unwrap(chainingFailDuringDelegationArgEmission)) + try unwrap(chainingFailAfterDelegation) } } diff --git a/test/SILGen/keypaths.swift b/test/SILGen/keypaths.swift index 3bc845e0519..854ae963147 100644 --- a/test/SILGen/keypaths.swift +++ b/test/SILGen/keypaths.swift @@ -182,3 +182,30 @@ func keyPathForExistentialMember() { _ = \P.z _ = \P.w } + +struct OptionalFields { + var x: S? +} +struct OptionalFields2 { + var y: OptionalFields? +} + +// CHECK-LABEL: sil hidden @_T08keypaths18keyPathForOptionalyyF +func keyPathForOptional() { + // CHECK: keypath $WritableKeyPath>, ( + // CHECK-SAME: stored_property #OptionalFields.x : $Optional>; + // CHECK-SAME: optional_force : $S) + _ = \OptionalFields.x! + // CHECK: keypath $KeyPath>, ( + // CHECK-SAME: stored_property #OptionalFields.x : $Optional>; + // CHECK-SAME: optional_chain : $S; + // CHECK-SAME: stored_property #S.y : $String; + // CHECK-SAME: optional_wrap : $Optional) + _ = \OptionalFields.x?.y + // CHECK: keypath $KeyPath>>, ( + // CHECK-SAME: root $OptionalFields2; + // CHECK-SAME: stored_property #OptionalFields2.y : $Optional; + // CHECK-SAME: optional_chain : $OptionalFields; + // CHECK-SAME: stored_property #OptionalFields.x : $Optional>) + _ = \OptionalFields2.y?.x +} diff --git a/test/SILGen/materializeForSet.swift b/test/SILGen/materializeForSet.swift index b479e9c2503..6706bffb17f 100644 --- a/test/SILGen/materializeForSet.swift +++ b/test/SILGen/materializeForSet.swift @@ -445,7 +445,7 @@ struct GenericSubscriptWitness : GenericSubscriptProtocol { // CHECK-NEXT: [[RESULT:%.*]] = tuple () // CHECK-NEXT: return [[RESULT]] : $() -// CHECK-LABEL sil hidden [transparent] [thunk] @_T017materializeForSet23GenericSubscriptWitnessVAA0dE8ProtocolA2aDP9subscriptqd__qd__clufmTW : $@convention(witness_method) <τ_0_0> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in τ_0_0, @inout GenericSubscriptWitness) -> (Builtin.RawPointer, Optional) { +// CHECK-LABEL: sil hidden [transparent] @_T017materializeForSet23GenericSubscriptWitnessV9subscriptxxclufm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in T, @inout GenericSubscriptWitness) -> (Builtin.RawPointer, Optional) { // CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*T, %3 : $*GenericSubscriptWitness): // CHECK-NEXT: [[BUFFER:%.*]] = alloc_value_buffer $T in %1 : $*Builtin.UnsafeValueBuffer // CHECK-NEXT: copy_addr %2 to [initialization] [[BUFFER]] : $*T diff --git a/test/SILGen/objc_bridging_any.swift b/test/SILGen/objc_bridging_any.swift index f8488bb2cf7..8b8443e7b64 100644 --- a/test/SILGen/objc_bridging_any.swift +++ b/test/SILGen/objc_bridging_any.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -Xllvm -sil-print-debuginfo -emit-silgen %s | %FileCheck %s +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -Xllvm -sil-print-debuginfo -emit-silgen -sil-serialize-witness-tables %s | %FileCheck %s // REQUIRES: objc_interop import Foundation diff --git a/test/SILGen/objc_enum.swift b/test/SILGen/objc_enum.swift index a47cf76b6e8..5ffd7a8daa0 100644 --- a/test/SILGen/objc_enum.swift +++ b/test/SILGen/objc_enum.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -sdk %S/Inputs -I %S/Inputs -enable-source-import %s -emit-silgen > %t.out +// RUN: %target-swift-frontend -sdk %S/Inputs -I %S/Inputs -enable-source-import %s -emit-silgen -sil-serialize-witness-tables > %t.out // RUN: %FileCheck -check-prefix=CHECK -check-prefix=CHECK-%target-ptrsize %s < %t.out // RUN: %FileCheck -check-prefix=NEGATIVE %s < %t.out diff --git a/test/SILGen/objc_imported_generic.swift b/test/SILGen/objc_imported_generic.swift index 02a0ac1ceb1..b34382836f1 100644 --- a/test/SILGen/objc_imported_generic.swift +++ b/test/SILGen/objc_imported_generic.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-silgen %s | %FileCheck %s +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-silgen -sil-serialize-witness-tables %s | %FileCheck %s // For integration testing, ensure we get through IRGen too. // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-ir -verify -DIRGEN_INTEGRATION_TEST %s diff --git a/test/SILGen/objc_witnesses.swift b/test/SILGen/objc_witnesses.swift index b9b7d6f474a..1f4ec2a1ebc 100644 --- a/test/SILGen/objc_witnesses.swift +++ b/test/SILGen/objc_witnesses.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -emit-silgen -sdk %S/Inputs -I %S/Inputs -enable-source-import %s | %FileCheck %s +// RUN: %target-swift-frontend -emit-silgen -sil-serialize-witness-tables -sdk %S/Inputs -I %S/Inputs -enable-source-import %s | %FileCheck %s // REQUIRES: objc_interop diff --git a/test/SILGen/super.swift b/test/SILGen/super.swift index 76c26da3317..17d71749021 100644 --- a/test/SILGen/super.swift +++ b/test/SILGen/super.swift @@ -83,49 +83,71 @@ public class GreatGrandchild : Grandchild { public class ChildToResilientParent : ResilientOutsideParent { // CHECK-LABEL: sil @_T05super22ChildToResilientParentC6methodyyF : $@convention(method) (@guaranteed ChildToResilientParent) -> () public override func method() { - // CHECK: [[COPY:%.*]] = copy_value %0 - // CHECK: super_method [[COPY]] : $ChildToResilientParent, #ResilientOutsideParent.method!1 : (ResilientOutsideParent) -> () -> (), $@convention(method) (@guaranteed ResilientOutsideParent) -> () - // CHECK: return + // CHECK: bb0([[SELF:%.*]] : $ChildToResilientParent): + // CHECK: [[COPY_SELF:%.*]] = copy_value [[SELF]] + // CHECK: [[UPCAST_SELF:%.*]] = upcast [[COPY_SELF]] + // CHECK: [[FUNC:%.*]] = super_method [[COPY_SELF]] : $ChildToResilientParent, #ResilientOutsideParent.method!1 : (ResilientOutsideParent) -> () -> (), $@convention(method) (@guaranteed ResilientOutsideParent) -> () + // CHECK: apply [[FUNC]]([[UPCAST_SELF]]) super.method() } + // CHECK: } // end sil function '_T05super22ChildToResilientParentC6methodyyF' // CHECK-LABEL: sil @_T05super22ChildToResilientParentC11classMethodyyFZ : $@convention(method) (@thick ChildToResilientParent.Type) -> () public override class func classMethod() { - // CHECK: super_method %0 : $@thick ChildToResilientParent.Type, #ResilientOutsideParent.classMethod!1 : (ResilientOutsideParent.Type) -> () -> (), $@convention(method) (@thick ResilientOutsideParent.Type) -> () - // CHECK: return + // CHECK: bb0([[METASELF:%.*]] : $@thick ChildToResilientParent.Type): + // CHECK: [[UPCAST_METASELF:%.*]] = upcast [[METASELF]] + // CHECK: [[FUNC:%.*]] = super_method [[SELF]] : $@thick ChildToResilientParent.Type, #ResilientOutsideParent.classMethod!1 : (ResilientOutsideParent.Type) -> () -> (), $@convention(method) (@thick ResilientOutsideParent.Type) -> () + // CHECK: apply [[FUNC]]([[UPCAST_METASELF]]) super.classMethod() } + // CHECK: } // end sil function '_T05super22ChildToResilientParentC11classMethodyyFZ' // CHECK-LABEL: sil @_T05super22ChildToResilientParentC11returnsSelfACXDyFZ : $@convention(method) (@thick ChildToResilientParent.Type) -> @owned ChildToResilientParent public class func returnsSelf() -> Self { - // CHECK: super_method %0 : $@thick ChildToResilientParent.Type, #ResilientOutsideParent.classMethod!1 : (ResilientOutsideParent.Type) -> () -> () + // CHECK: bb0([[METASELF:%.*]] : $@thick ChildToResilientParent.Type): + // CHECK: [[CAST_METASELF:%.*]] = unchecked_trivial_bit_cast [[METASELF]] : $@thick ChildToResilientParent.Type to $@thick @dynamic_self ChildToResilientParent.Type + // CHECK: [[UPCAST_CAST_METASELF:%.*]] = upcast [[CAST_METASELF]] : $@thick @dynamic_self ChildToResilientParent.Type to $@thick ResilientOutsideParent.Type + // CHECK: [[FUNC:%.*]] = super_method [[METASELF]] : $@thick ChildToResilientParent.Type, #ResilientOutsideParent.classMethod!1 : (ResilientOutsideParent.Type) -> () -> () + // CHECK: apply [[FUNC]]([[UPCAST_CAST_METASELF]]) // CHECK: unreachable super.classMethod() } + // CHECK: } // end sil function '_T05super22ChildToResilientParentC11returnsSelfACXDyFZ' } public class ChildToFixedParent : OutsideParent { // CHECK-LABEL: sil @_T05super18ChildToFixedParentC6methodyyF : $@convention(method) (@guaranteed ChildToFixedParent) -> () public override func method() { - // CHECK: [[COPY:%.*]] = copy_value %0 - // CHECK: super_method [[COPY]] : $ChildToFixedParent, #OutsideParent.method!1 : (OutsideParent) -> () -> (), $@convention(method) (@guaranteed OutsideParent) -> () - // CHECK: return + // CHECK: bb0([[SELF:%.*]] : $ChildToFixedParent): + // CHECK: [[COPY_SELF:%.*]] = copy_value [[SELF]] + // CHECK: [[UPCAST_COPY_SELF:%.*]] = upcast [[COPY_SELF]] + // CHECK: [[FUNC:%.*]] = super_method [[COPY_SELF]] : $ChildToFixedParent, #OutsideParent.method!1 : (OutsideParent) -> () -> (), $@convention(method) (@guaranteed OutsideParent) -> () + // CHECK: apply [[FUNC]]([[UPCAST_COPY_SELF]]) super.method() } + // CHECK: } // end sil function '_T05super18ChildToFixedParentC6methodyyF' // CHECK-LABEL: sil @_T05super18ChildToFixedParentC11classMethodyyFZ : $@convention(method) (@thick ChildToFixedParent.Type) -> () public override class func classMethod() { - // CHECK: super_method %0 : $@thick ChildToFixedParent.Type, #OutsideParent.classMethod!1 : (OutsideParent.Type) -> () -> (), $@convention(method) (@thick OutsideParent.Type) -> () - // CHECK: return + // CHECK: bb0([[SELF:%.*]] : $@thick ChildToFixedParent.Type): + // CHECK: [[UPCAST_SELF:%.*]] = upcast [[SELF]] + // CHECK: [[FUNC:%.*]] = super_method [[SELF]] : $@thick ChildToFixedParent.Type, #OutsideParent.classMethod!1 : (OutsideParent.Type) -> () -> (), $@convention(method) (@thick OutsideParent.Type) -> () + // CHECK: apply [[FUNC]]([[UPCAST_SELF]]) super.classMethod() } + // CHECK: } // end sil function '_T05super18ChildToFixedParentC11classMethodyyFZ' // CHECK-LABEL: sil @_T05super18ChildToFixedParentC11returnsSelfACXDyFZ : $@convention(method) (@thick ChildToFixedParent.Type) -> @owned ChildToFixedParent public class func returnsSelf() -> Self { - // CHECK: super_method %0 : $@thick ChildToFixedParent.Type, #OutsideParent.classMethod!1 : (OutsideParent.Type) -> () -> () - // CHECK: unreachable + // CHECK: bb0([[SELF:%.*]] : $@thick ChildToFixedParent.Type): + // CHECK: [[FIRST_CAST:%.*]] = unchecked_trivial_bit_cast [[SELF]] + // CHECK: [[SECOND_CAST:%.*]] = upcast [[FIRST_CAST]] + // CHECK: [[FUNC:%.*]] = super_method [[SELF]] : $@thick ChildToFixedParent.Type, #OutsideParent.classMethod!1 : (OutsideParent.Type) -> () -> () + // CHECK: apply [[FUNC]]([[SECOND_CAST]]) + // CHECK: unreachable super.classMethod() } + // CHECK: } // end sil function '_T05super18ChildToFixedParentC11returnsSelfACXDyFZ' } public extension ResilientOutsideChild { @@ -150,11 +172,12 @@ public class GenericDerived : GenericBase { { super.method() }() + // CHECK: } // end sil function '_T05super14GenericDerivedC6methodyyFyycfU_' // CHECK-LABEL: sil private @_T05super14GenericDerivedC6methodyyF13localFunctionL_yylF : $@convention(thin) (@owned GenericDerived) -> () // CHECK: upcast {{.*}} : $GenericDerived to $GenericBase // CHECK: return - + // CHECK: } // end sil function '_T05super14GenericDerivedC6methodyyF13localFunctionL_yylF' func localFunction() { super.method() } @@ -166,6 +189,7 @@ public class GenericDerived : GenericBase { func genericFunction(_: U) { super.method() } + // CHECK: } // end sil function '_T05super14GenericDerivedC6methodyyF15genericFunctionL_yqd__r__lF' genericFunction(0) } } diff --git a/test/SILGen/switch.swift b/test/SILGen/switch.swift index 41b615fe74f..c5275b40a9e 100644 --- a/test/SILGen/switch.swift +++ b/test/SILGen/switch.swift @@ -1071,8 +1071,8 @@ func testMultiPatternsWithOuterScopeSameNamedVar(base: Int?, filter: Int?) { case (.some(let base), .some(let filter)): // CHECK: bb2(%10 : $Int): - // CHECK-NEXT: debug_value %10 : $Int, let, name "base" - // CHECK-NEXT: debug_value %8 : $Int, let, name "filter" + // CHECK-NEXT: debug_value %8 : $Int, let, name "base" + // CHECK-NEXT: debug_value %10 : $Int, let, name "filter" print("both: \(base), \(filter)") case (.some(let base), .none), (.none, .some(let base)): // CHECK: bb3: diff --git a/test/SILGen/testable-multifile.swift b/test/SILGen/testable-multifile.swift index 7e7387147a5..fc38f82295f 100644 --- a/test/SILGen/testable-multifile.swift +++ b/test/SILGen/testable-multifile.swift @@ -3,9 +3,9 @@ // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -emit-module %S/Inputs/TestableMultifileHelper.swift -enable-testing -o %t -// RUN: %target-swift-frontend -emit-silgen -I %t %s %S/testable-multifile-other.swift -module-name main | %FileCheck %s -// RUN: %target-swift-frontend -emit-silgen -I %t %S/testable-multifile-other.swift %s -module-name main | %FileCheck %s -// RUN: %target-swift-frontend -emit-silgen -I %t -primary-file %s %S/testable-multifile-other.swift -module-name main | %FileCheck %s +// RUN: %target-swift-frontend -emit-silgen -sil-serialize-witness-tables -I %t %s %S/testable-multifile-other.swift -module-name main | %FileCheck %s +// RUN: %target-swift-frontend -emit-silgen -sil-serialize-witness-tables -I %t %S/testable-multifile-other.swift %s -module-name main | %FileCheck %s +// RUN: %target-swift-frontend -emit-silgen -sil-serialize-witness-tables -I %t -primary-file %s %S/testable-multifile-other.swift -module-name main | %FileCheck %s // Just make sure we don't crash later on. // RUN: %target-swift-frontend -emit-ir -I %t -primary-file %s %S/testable-multifile-other.swift -module-name main -o /dev/null diff --git a/test/SILGen/variadic-subscript-single-arg.swift b/test/SILGen/variadic-subscript-single-arg.swift new file mode 100644 index 00000000000..833f6cd58ae --- /dev/null +++ b/test/SILGen/variadic-subscript-single-arg.swift @@ -0,0 +1,9 @@ +// RUN: %target-swift-frontend -emit-silgen -verify %s + +struct Butt { + subscript(butts: Int...) -> Int { + return 0 + } +} + +_ = Butt()[1] diff --git a/test/SILGen/vtables.swift b/test/SILGen/vtables.swift index dfc100b731c..aee60e79eaf 100644 --- a/test/SILGen/vtables.swift +++ b/test/SILGen/vtables.swift @@ -130,11 +130,11 @@ class Derived : Base { } } - // CHECK: sil_vtable RequiredInitDerived { // CHECK-NEXT: #SimpleInitBase.init!initializer.1: {{.*}} : _T07vtables19RequiredInitDerivedC{{[_0-9a-zA-Z]*}}fc -// CHECK-NEXT #RequiredInitDerived.init!allocator.1: {{.*}} : _TFC7vtables19RequiredInitDerivedC -// CHECK-NEXT} +// CHECK-NEXT: #RequiredInitDerived.init!allocator.1: {{.*}} : _T07vtables19RequiredInitDerivedC +// CHECK-NEXT: #RequiredInitDerived.deinit!deallocator: _T07vtables19RequiredInitDerivedCfD +// CHECK-NEXT: } class SimpleInitBase { } diff --git a/test/SILGen/witness_accessibility.swift b/test/SILGen/witness_accessibility.swift index bd06a6a7903..2b1b7d88dc1 100644 --- a/test/SILGen/witness_accessibility.swift +++ b/test/SILGen/witness_accessibility.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen %s | %FileCheck %s +// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen -sil-serialize-witness-tables %s | %FileCheck %s public protocol P { func publicRequirement() diff --git a/test/SILGen/witness_same_type.swift b/test/SILGen/witness_same_type.swift index 963e2d44ce0..04de7b6305c 100644 --- a/test/SILGen/witness_same_type.swift +++ b/test/SILGen/witness_same_type.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -emit-silgen %s | %FileCheck %s +// RUN: %target-swift-frontend -emit-silgen -sil-serialize-witness-tables %s | %FileCheck %s // RUN: %target-swift-frontend -emit-ir %s protocol Fooable { diff --git a/test/SILGen/witness_tables.swift b/test/SILGen/witness_tables.swift index 59315347d35..bf23c2d6e9b 100644 --- a/test/SILGen/witness_tables.swift +++ b/test/SILGen/witness_tables.swift @@ -1,8 +1,8 @@ -// RUN: %target-swift-frontend -emit-silgen -I %S/Inputs -enable-source-import %s -disable-objc-attr-requires-foundation-module > %t.sil +// RUN: %target-swift-frontend -emit-silgen -sil-serialize-witness-tables -I %S/Inputs -enable-source-import %s -disable-objc-attr-requires-foundation-module > %t.sil // RUN: %FileCheck -check-prefix=TABLE -check-prefix=TABLE-ALL %s < %t.sil // RUN: %FileCheck -check-prefix=SYMBOL %s < %t.sil -// RUN: %target-swift-frontend -emit-silgen -I %S/Inputs -enable-source-import %s -disable-objc-attr-requires-foundation-module -enable-testing > %t.testable.sil +// RUN: %target-swift-frontend -emit-silgen -sil-serialize-witness-tables -I %S/Inputs -enable-source-import %s -disable-objc-attr-requires-foundation-module -enable-testing > %t.testable.sil // RUN: %FileCheck -check-prefix=TABLE-TESTABLE -check-prefix=TABLE-ALL %s < %t.testable.sil // RUN: %FileCheck -check-prefix=SYMBOL-TESTABLE %s < %t.testable.sil diff --git a/test/SILOptimizer/access_enforcement_noescape.swift b/test/SILOptimizer/access_enforcement_noescape.swift index 760cf4c07c7..d9c44561671 100644 --- a/test/SILOptimizer/access_enforcement_noescape.swift +++ b/test/SILOptimizer/access_enforcement_noescape.swift @@ -1,19 +1,14 @@ -// RUN: %target-swift-frontend -enforce-exclusivity=checked -Onone -emit-sil -parse-as-library %s | %FileCheck %s +// RUN: %target-swift-frontend -enforce-exclusivity=checked -Onone -emit-sil -swift-version 4 -verify -parse-as-library %s +// RUN: %target-swift-frontend -enforce-exclusivity=checked -Onone -emit-sil -swift-version 3 -parse-as-library %s | %FileCheck %s // REQUIRES: asserts // This tests SILGen and AccessEnforcementSelection as a single set of tests. // (Some static/dynamic enforcement selection is done in SILGen, and some is // deferred. That may change over time but we want the outcome to be the same). // -// Each FIXME line is a case that the current implementation misses. -// The model is currently being refined, so this isn't set in stone. -// -// TODO: Move all static cases (search for // Error:) into -// a set of -verify tests (noescape_static_diagnostics.swift). -// and a set of separate SILGen-only tests to check [unknown] markers. -// -// TODO: Ensure that each dynamic case is covered by -// Interpreter/enforce_exclusive_access.swift. +// These tests attempt to fully cover the possibilities of reads and +// modifications to captures along with `inout` arguments on both the caller and +// callee side. // Helper func doOne(_ f: () -> ()) { @@ -26,13 +21,8 @@ func doTwo(_: ()->(), _: ()->()) {} // Helper func doOneInout(_: ()->(), _: inout Int) {} -// FIXME: statically prohibit a call to a non-escaping closure -// parameter using another non-escaping closure parameter as an argument. -func reentrantNoescape(fn: (() -> ()) -> ()) { - fn { fn {} } -} - // Error: Cannot capture nonescaping closure. +// This triggers an early diagnostics, so it's handled in inout_capture_disgnostics.swift. // func reentrantCapturedNoescape(fn: (() -> ()) -> ()) { // let c = { fn {} } // fn(c) @@ -54,8 +44,7 @@ func nestedNoEscape(f: inout Frob) { // closure #1 in nestedNoEscape(f:) // CHECK-LABEL: sil private @_T027access_enforcement_noescape14nestedNoEscapeyAA4FrobVz1f_tFyycfU_ : $@convention(thin) (@inout_aliasable Frob) -> () { -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Frob -// CHECK: [[ACCESS:%.*]] = begin_access [modify] +// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Frob // CHECK: %{{.*}} = apply %{{.*}}([[ACCESS]]) : $@convention(method) (@inout Frob) -> () // CHECK: end_access [[ACCESS]] : $*Frob // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape14nestedNoEscapeyAA4FrobVz1f_tFyycfU_' @@ -63,60 +52,54 @@ func nestedNoEscape(f: inout Frob) { // Allow aliased noescape reads. func readRead() { var x = 3 - // Around the call: [read] [static] // Inside each closure: [read] [static] doTwo({ _ = x }, { _ = x }) x = 42 } // CHECK-LABEL: sil hidden @_T027access_enforcement_noescape8readReadyyF : $@convention(thin) () -> () { // CHECK: [[ALLOC:%.*]] = alloc_stack $Int, var, name "x" -// CHECK-NOT: begin_access [read] [dynamic] -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [read] [static] [[ALLOC]] : $*Int -// CHECK-NOT: begin_access [read] [dynamic] +// CHECK-NOT: begin_access // CHECK: apply -// FIXME-CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape8readReadyyF' // closure #1 in readRead() // CHECK-LABEL: sil private @_T027access_enforcement_noescape8readReadyyFyycfU_ : $@convention(thin) (@inout_aliasable Int) -> () { -// CHECK-NOT: [[ACCESS:%.*]] = begin_access [read] [dynamic] -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK-NOT: begin_access [read] [dynamic] +// CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int +// CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape8readReadyyFyycfU_' // closure #2 in readRead() // CHECK-LABEL: sil private @_T027access_enforcement_noescape8readReadyyFyycfU0_ : $@convention(thin) (@inout_aliasable Int) -> () { -// CHECK-NOT: [[ACCESS:%.*]] = begin_access [read] [dynamic] -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK-NOT: begin_access [read] [dynamic] +// CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int +// CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape8readReadyyFyycfU0_' // Allow aliased noescape reads of an `inout` arg. func inoutReadRead(x: inout Int) { - // Around the call: [read] [static] // Inside each closure: [read] [static] doTwo({ _ = x }, { _ = x }) } // CHECK-LABEL: sil hidden @_T027access_enforcement_noescape09inoutReadE0ySiz1x_tF : $@convention(thin) (@inout Int) -> () { // CHECK: [[PA1:%.*]] = partial_apply // CHECK: [[PA2:%.*]] = partial_apply -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int +// CHECK-NOT: begin_access // CHECK: apply %{{.*}}([[PA1]], [[PA2]]) -// FIXME-CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape09inoutReadE0ySiz1x_tF' // closure #1 in inoutReadRead(x:) // CHECK-LABEL: sil private @_T027access_enforcement_noescape09inoutReadE0ySiz1x_tFyycfU_ : $@convention(thin) (@inout_aliasable Int) -> () { -// CHECK-NOT: [[ACCESS:%.*]] = begin_access [read] [dynamic] -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK-NOT: begin_access [read] [dynamic] +// CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int +// CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape09inoutReadE0ySiz1x_tFyycfU_' // closure #2 in inoutReadRead(x:) // CHECK-LABEL: sil private @_T027access_enforcement_noescape09inoutReadE0ySiz1x_tFyycfU0_ : $@convention(thin) (@inout_aliasable Int) -> () { -// CHECK-NOT: [[ACCESS:%.*]] = begin_access [read] [dynamic] -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK-NOT: begin_access [read] [dynamic] +// CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int +// CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape09inoutReadE0ySiz1x_tFyycfU0_' // Allow aliased noescape read + boxed read. @@ -131,6 +114,7 @@ func readBoxRead() { // CHECK-LABEL: sil hidden @_T027access_enforcement_noescape11readBoxReadyyF : $@convention(thin) () -> () { // CHECK: [[PA1:%.*]] = partial_apply // CHECK: [[PA2:%.*]] = partial_apply +// CHECK-NOT: begin_access // CHECK: apply %{{.*}}([[PA1]], [[PA2]]) // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape11readBoxReadyyF' @@ -143,10 +127,8 @@ func readBoxRead() { // closure #2 in readBoxRead() // CHECK-LABEL: sil private @_T027access_enforcement_noescape11readBoxReadyyFyycfU0_ : $@convention(thin) (@inout_aliasable Int) -> () { -// FIXME-CHECK-LABEL: sil private @_T027access_enforcement_noescape11readBoxReadyyFyycfU0_ : $@convention(thin) (@owned { var Int }) -> () { -// FIXME-CHECK: [[ADDR:%.*]] = project_box %0 : ${ var Int }, 0 -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [read] [dynamic] [[ADDR]] : $*Int -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK: [[ACCESS:%.*]] = begin_access [read] [dynamic] %0 : $*Int +// CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape11readBoxReadyyFyycfU0_' // Error: cannout capture inout. @@ -159,7 +141,6 @@ func readBoxRead() { // Allow aliased noescape read + write. func readWrite() { var x = 3 - // Around the call: [modify] [static] // Inside closure 1: [read] [static] // Inside closure 2: [modify] [static] doTwo({ _ = x }, { x = 42 }) @@ -167,28 +148,26 @@ func readWrite() { // CHECK-LABEL: sil hidden @_T027access_enforcement_noescape9readWriteyyF : $@convention(thin) () -> () { // CHECK: [[PA1:%.*]] = partial_apply // CHECK: [[PA2:%.*]] = partial_apply -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int +// CHECK-NOT: begin_access // CHECK: apply %{{.*}}([[PA1]], [[PA2]]) -// FIXME-CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape9readWriteyyF' // closure #1 in readWrite() // CHECK-LABEL: sil private @_T027access_enforcement_noescape9readWriteyyFyycfU_ : $@convention(thin) (@inout_aliasable Int) -> () { // CHECK-NOT: [[ACCESS:%.*]] = begin_access [read] [dynamic] -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int +// CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape9readWriteyyFyycfU_' // closure #2 in readWrite() // CHECK-LABEL: sil private @_T027access_enforcement_noescape9readWriteyyFyycfU0_ : $@convention(thin) (@inout_aliasable Int) -> () { // CHECK-NOT: [[ACCESS:%.*]] = begin_access [modify] [dynamic] -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int +// CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape9readWriteyyFyycfU0_' // Allow aliased noescape read + write of an `inout` arg. func inoutReadWrite(x: inout Int) { - // Around the call: [modify] [static] // Inside closure 1: [read] [static] // Inside closure 2: [modify] [static] doTwo({ _ = x }, { x = 3 }) @@ -197,33 +176,22 @@ func inoutReadWrite(x: inout Int) { // CHECK-LABEL: sil hidden @_T027access_enforcement_noescape14inoutReadWriteySiz1x_tF : $@convention(thin) (@inout Int) -> () { // CHECK: [[PA1:%.*]] = partial_apply // CHECK: [[PA2:%.*]] = partial_apply -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int // CHECK: apply %{{.*}}([[PA1]], [[PA2]]) -// FIXME-CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape14inoutReadWriteySiz1x_tF' // closure #1 in inoutReadWrite(x:) // CHECK-LABEL: sil private @_T027access_enforcement_noescape14inoutReadWriteySiz1x_tFyycfU_ : $@convention(thin) (@inout_aliasable Int) -> () { -// CHECK-NOT: [[ACCESS:%.*]] = begin_access [read] [dynamic] -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int +// CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape14inoutReadWriteySiz1x_tFyycfU_' // closure #2 in inoutReadWrite(x:) // CHECK-LABEL: sil private @_T027access_enforcement_noescape14inoutReadWriteySiz1x_tFyycfU0_ : $@convention(thin) (@inout_aliasable Int) -> () { -// CHECK-NOT: [[ACCESS:%.*]] = begin_access [modify] [dynamic] -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int +// CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape14inoutReadWriteySiz1x_tFyycfU0_' -// FIXME: Trap on aliased boxed read + noescape write. -// -// Note: There's no actual exclusivity danger here, because `c` is -// passed to a noescape argument and is never itself -// captured. However, SILGen conservatively assumes that the -// assignment `let c =` captures the closure. Later we could refine -// the rules to recognize obviously nonescpaping closures. func readBoxWrite() { var x = 3 let c = { _ = x } @@ -247,10 +215,8 @@ func readBoxWrite() { // closure #2 in readBoxWrite() // CHECK-LABEL: sil private @_T027access_enforcement_noescape12readBoxWriteyyFyycfU0_ : $@convention(thin) (@inout_aliasable Int) -> () { -// FIXME-CHECK-LABEL: sil private @_T027access_enforcement_noescape12readBoxWriteyyFyycfU0_ : $@convention(thin) (@owned { var Int }) -> () { -// FIXME-CHECK: [[ADDR:%.*]] = project_box %0 : ${ var Int }, 0 -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [read] [dynamic] [[ADDR]] : $*Int -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] %0 : $*Int +// CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape12readBoxWriteyyFyycfU0_' // Error: cannout capture inout. @@ -259,9 +225,6 @@ func readBoxWrite() { // doTwo({ x = 42 }, c) // } -// FIXME: Trap on aliased noescape read + boxed write. -// -// See the note above. func readWriteBox() { var x = 3 let c = { x = 42 } @@ -286,10 +249,8 @@ func readWriteBox() { // closure #2 in readWriteBox() // CHECK-LABEL: sil private @_T027access_enforcement_noescape12readWriteBoxyyFyycfU0_ : $@convention(thin) (@inout_aliasable Int) -> () { -// FIXME-CHECK-LABEL: sil private @_T027access_enforcement_noescape12readWriteBoxyyFyycfU0_ : $@convention(thin) ((@owned { var Int }) -> () { -// FIXME-CHECK: [[ADDR:%.*]] = project_box %0 : ${ var Int }, 0 -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[ADDR]] : $*Int -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK: [[ACCESS:%.*]] = begin_access [read] [dynamic] %0 : $*Int +// CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape12readWriteBoxyyFyycfU0_' // Error: cannout capture inout. @@ -301,54 +262,50 @@ func readWriteBox() { // Error: noescape read + write inout. func readWriteInout() { var x = 3 - // Around the call: [read] [static] - // Around the call: [modify] [static] // Error + // Around the call: [modify] [static] // Inside closure: [modify] [static] + // expected-error@+2{{overlapping accesses to 'x', but modification requires exclusive access; consider copying to a local variable}} + // expected-note@+1{{conflicting access is here}} doOneInout({ _ = x }, &x) } // CHECK-LABEL: sil hidden @_T027access_enforcement_noescape14readWriteInoutyyF : $@convention(thin) () -> () { // CHECK: [[PA1:%.*]] = partial_apply -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int -// FIXME-CHECK: [[ACCESS2:%.*]] = begin_access [modify] [static] %0 : $*Int -// FIXME-CHECK: apply %{{.*}}([[PA1]], [[ACCESS2]]) -// FIXME-CHECK: end_access [[ACCESS2]] -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK: [[ACCESS2:%.*]] = begin_access [modify] [static] %0 : $*Int +// CHECK: apply %{{.*}}([[PA1]], [[ACCESS2]]) +// CHECK: end_access [[ACCESS2]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape14readWriteInoutyyF' // closure #1 in readWriteInout() // CHECK-LABEL: sil private @_T027access_enforcement_noescape14readWriteInoutyyFyycfU_ : $@convention(thin) (@inout_aliasable Int) -> () { -// CHECK-NOT: [[ACCESS:%.*]] = begin_access [read] [dynamic] -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int +// CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape14readWriteInoutyyFyycfU_' // Error: noescape read + write inout of an inout. func inoutReadWriteInout(x: inout Int) { - // Around the call: [read] [static] - // Around the call: [modify] [static] // Error + // Around the call: [modify] [static] // Inside closure: [modify] [static] + // expected-error@+2{{overlapping accesses to 'x', but modification requires exclusive access; consider copying to a local variable}} + // expected-note@+1{{conflicting access is here}} doOneInout({ _ = x }, &x) } // CHECK-LABEL: sil hidden @_T027access_enforcement_noescape19inoutReadWriteInoutySiz1x_tF : $@convention(thin) (@inout Int) -> () { // CHECK: [[PA1:%.*]] = partial_apply -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int -// FIXME-CHECK: [[ACCESS2:%.*]] = begin_access [modify] [static] %0 : $*Int -// FIXME-CHECK: apply %{{.*}}([[PA1]], [[ACCESS2]]) -// FIXME-CHECK: end_access [[ACCESS2]] -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK: [[ACCESS2:%.*]] = begin_access [modify] [static] %0 : $*Int +// CHECK: apply %{{.*}}([[PA1]], [[ACCESS2]]) +// CHECK: end_access [[ACCESS2]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape19inoutReadWriteInoutySiz1x_tF' // closure #1 in inoutReadWriteInout(x:) // CHECK-LABEL: sil private @_T027access_enforcement_noescape19inoutReadWriteInoutySiz1x_tFyycfU_ : $@convention(thin) (@inout_aliasable Int) -> () { -// CHECK-NOT: [[ACCESS:%.*]] = begin_access [read] [dynamic] -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK: [[ACCESS:%.*]] = begin_access [read] [static] %0 : $*Int +// CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape19inoutReadWriteInoutySiz1x_tFyycfU_' -// Trap on boxed read + write inout. -// FIXME: Passing a captured var as inout needs dynamic enforcement. +// Traps on boxed read + write inout. +// Covered by Interpreter/enforce_exclusive_access.swift. func readBoxWriteInout() { var x = 3 let c = { _ = x } @@ -359,9 +316,9 @@ func readBoxWriteInout() { // CHECK-LABEL: sil hidden @_T027access_enforcement_noescape17readBoxWriteInoutyyF : $@convention(thin) () -> () { // CHECK: [[PA1:%.*]] = partial_apply -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] %0 : $*Int -// FIXME-CHECK: apply %{{.*}}([[PA1]], [[ACCESS]]) -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] %1 : $*Int +// CHECK: apply %{{.*}}([[PA1]], [[ACCESS]]) +// CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape17readBoxWriteInoutyyF' // closure #1 in readBoxWriteInout() @@ -372,6 +329,7 @@ func readBoxWriteInout() { // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape17readBoxWriteInoutyyFyycfU_' // Error: inout cannot be captured. +// This triggers an early diagnostics, so it's handled in inout_capture_disgnostics.swift. // func inoutReadBoxWriteInout(x: inout Int) { // let c = { _ = x } // doOneInout(c, &x) @@ -380,7 +338,6 @@ func readBoxWriteInout() { // Allow aliased noescape write + write. func writeWrite() { var x = 3 - // Around the call: [modify] [static] // Inside closure 1: [modify] [static] // Inside closure 2: [modify] [static] doTwo({ x = 42 }, { x = 87 }) @@ -390,29 +347,25 @@ func writeWrite() { // CHECK-LABEL: sil hidden @_T027access_enforcement_noescape10writeWriteyyF : $@convention(thin) () -> () { // CHECK: [[PA1:%.*]] = partial_apply // CHECK: [[PA2:%.*]] = partial_apply -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int -// FIXME-CHECK: apply %{{.*}}([[PA1]], [[PA2]]) -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK-NOT: begin_access +// CHECK: apply %{{.*}}([[PA1]], [[PA2]]) // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape10writeWriteyyF' // closure #1 in writeWrite() // CHECK-LABEL: sil private @_T027access_enforcement_noescape10writeWriteyyFyycfU_ : $@convention(thin) (@inout_aliasable Int) -> () { -// CHECK-NOT: [[ACCESS:%.*]] = begin_access [modify] [dynamic] -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int +// CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape10writeWriteyyFyycfU_' // closure #2 in writeWrite() // CHECK-LABEL: sil private @_T027access_enforcement_noescape10writeWriteyyFyycfU0_ : $@convention(thin) (@inout_aliasable Int) -> () { -// CHECK-NOT: [[ACCESS:%.*]] = begin_access [modify] [dynamic] -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int +// CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape10writeWriteyyFyycfU0_' // Allow aliased noescape write + write of an `inout` arg. func inoutWriteWrite(x: inout Int) { - // Around the call: [modify] [static] // Inside closure 1: [modify] [static] // Inside closure 2: [modify] [static] doTwo({ x = 42}, { x = 87 }) @@ -421,28 +374,24 @@ func inoutWriteWrite(x: inout Int) { // CHECK-LABEL: sil hidden @_T027access_enforcement_noescape010inoutWriteE0ySiz1x_tF : $@convention(thin) (@inout Int) -> () { // CHECK: [[PA1:%.*]] = partial_apply // CHECK: [[PA2:%.*]] = partial_apply -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int -// FIXME-CHECK: apply %{{.*}}([[PA1]], [[PA2]]) -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK-NOT: begin_access +// CHECK: apply %{{.*}}([[PA1]], [[PA2]]) // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape010inoutWriteE0ySiz1x_tF' // closure #1 in inoutWriteWrite(x:) // CHECK-LABEL: sil private @_T027access_enforcement_noescape010inoutWriteE0ySiz1x_tFyycfU_ : $@convention(thin) (@inout_aliasable Int) -> () { -// CHECK-NOT: [[ACCESS:%.*]] = begin_access [modify] [dynamic] -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int +// CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape010inoutWriteE0ySiz1x_tFyycfU_' // closure #2 in inoutWriteWrite(x:) // CHECK-LABEL: sil private @_T027access_enforcement_noescape010inoutWriteE0ySiz1x_tFyycfU0_ : $@convention(thin) (@inout_aliasable Int) -> () { -// CHECK-NOT: [[ACCESS:%.*]] = begin_access [modify] [dynamic] -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int +// CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape010inoutWriteE0ySiz1x_tFyycfU0_' -// FIXME: Trap on aliased boxed write + noescape write. -// -// See the note above. +// Traps on aliased boxed write + noescape write. +// Covered by Interpreter/enforce_exclusive_access.swift. func writeWriteBox() { var x = 3 let c = { x = 87 } @@ -455,8 +404,8 @@ func writeWriteBox() { // CHECK-LABEL: sil hidden @_T027access_enforcement_noescape13writeWriteBoxyyF : $@convention(thin) () -> () { // CHECK: [[PA1:%.*]] = partial_apply // CHECK: [[PA2:%.*]] = partial_apply -// FIXME-CHECK-NOT: begin_access -// FIXME-CHECK: apply %{{.*}}([[PA1]], [[PA2]]) +// CHECK-NOT: begin_access +// CHECK: apply %{{.*}}([[PA2]], [[PA1]]) // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape13writeWriteBoxyyF' // closure #1 in writeWriteBox() @@ -468,9 +417,8 @@ func writeWriteBox() { // closure #2 in writeWriteBox() // CHECK-LABEL: sil private @_T027access_enforcement_noescape13writeWriteBoxyyFyycfU0_ : $@convention(thin) (@inout_aliasable Int) -> () { -// FIXME-CHECK: [[ADDR:%.*]] = project_box %0 : ${ var Int }, 0 -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[ADDR]] : $*Int -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] %0 : $*Int +// CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape13writeWriteBoxyyFyycfU0_' // Error: inout cannot be captured. @@ -483,53 +431,50 @@ func writeWriteBox() { func writeWriteInout() { var x = 3 // Around the call: [modify] [static] - // Around the call: [modify] [static] // Error // Inside closure: [modify] [static] + // expected-error@+2{{overlapping accesses to 'x', but modification requires exclusive access; consider copying to a local variable}} + // expected-note@+1{{conflicting access is here}} doOneInout({ x = 42 }, &x) } // CHECK-LABEL: sil hidden @_T027access_enforcement_noescape15writeWriteInoutyyF : $@convention(thin) () -> () { // CHECK: [[PA1:%.*]] = partial_apply -// FIXME-CHECK: [[ACCESS1:%.*]] = begin_access [modify] [static] %0 : $*Int -// FIXME-CHECK: [[ACCESS2:%.*]] = begin_access [modify] [static] %0 : $*Int -// FIXME-CHECK: apply %{{.*}}([[PA1]], [[ACCESS2]]) -// FIXME-CHECK: end_access [[ACCESS2]] -// FIXME-CHECK: end_access [[ACCESS1]] +// CHECK: [[ACCESS2:%.*]] = begin_access [modify] [static] %0 : $*Int +// CHECK: apply %{{.*}}([[PA1]], [[ACCESS2]]) +// CHECK: end_access [[ACCESS2]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape15writeWriteInoutyyF' // closure #1 in writeWriteInout() // CHECK-LABEL: sil private @_T027access_enforcement_noescape15writeWriteInoutyyFyycfU_ : $@convention(thin) (@inout_aliasable Int) -> () { -// CHECK-NOT: [[ACCESS:%.*]] = begin_access [modify] [dynamic] -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int +// CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape15writeWriteInoutyyFyycfU_' // Error: on noescape write + write inout. func inoutWriteWriteInout(x: inout Int) { // Around the call: [modify] [static] - // Around the call: [modify] [static] // Error // Inside closure: [modify] [static] + // expected-error@+2{{overlapping accesses to 'x', but modification requires exclusive access; consider copying to a local variable}} + // expected-note@+1{{conflicting access is here}} doOneInout({ x = 42 }, &x) } // inoutWriteWriteInout(x:) // CHECK-LABEL: sil hidden @_T027access_enforcement_noescape010inoutWriteE5InoutySiz1x_tF : $@convention(thin) (@inout Int) -> () { // CHECK: [[PA1:%.*]] = partial_apply -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int -// FIXME-CHECK: [[ACCESS2:%.*]] = begin_access [modify] [static] %0 : $*Int -// FIXME-CHECK: apply %{{.*}}([[PA1]], [[ACCESS2]]) -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK: [[ACCESS2:%.*]] = begin_access [modify] [static] %0 : $*Int +// CHECK: apply %{{.*}}([[PA1]], [[ACCESS2]]) +// CHECK: end_access [[ACCESS2]] // CHECK-LABEL: // end sil function '_T027access_enforcement_noescape010inoutWriteE5InoutySiz1x_tF' // closure #1 in inoutWriteWriteInout(x:) // CHECK-LABEL: sil private @_T027access_enforcement_noescape010inoutWriteE5InoutySiz1x_tFyycfU_ : $@convention(thin) (@inout_aliasable Int) -> () { -// CHECK-NOT: [[ACCESS:%.*]] = begin_access [modify] [dynamic] -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] %0 : $*Int +// CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape010inoutWriteE5InoutySiz1x_tFyycfU_' -// Trap on boxed write + write inout. -// FIXME: Passing a captured var as inout needs dynamic enforcement. +// Traps on boxed write + write inout. +// Covered by Interpreter/enforce_exclusive_access.swift. func writeBoxWriteInout() { var x = 3 let c = { x = 42 } @@ -540,9 +485,9 @@ func writeBoxWriteInout() { // CHECK-LABEL: sil hidden @_T027access_enforcement_noescape18writeBoxWriteInoutyyF : $@convention(thin) () -> () { // CHECK: [[PA1:%.*]] = partial_apply -// FIXME-CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] %0 : $*Int -// FIXME-CHECK: apply %{{.*}}([[PA1]], [[ACCESS]]) -// FIXME-CHECK: end_access [[ACCESS]] +// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] %1 : $*Int +// CHECK: apply %{{.*}}([[PA1]], [[ACCESS]]) +// CHECK: end_access [[ACCESS]] // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape18writeBoxWriteInoutyyF' // closure #1 in writeBoxWriteInout() @@ -553,7 +498,67 @@ func writeBoxWriteInout() { // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape18writeBoxWriteInoutyyFyycfU_' // Error: Cannot capture inout +// This triggers an early diagnostics, so it's handled in inout_capture_disgnostics.swift. // func inoutWriteBoxWriteInout(x: inout Int) { // let c = { x = 42 } // doOneInout(c, &x) // } + +// Helper +func doBlockInout(_: @convention(block) ()->(), _: inout Int) {} + +// FIXME: This case could be statically enforced, but requires quite a bit of SIL pattern matching. +func readBlockWriteInout() { + var x = 3 + // Around the call: [modify] [static] + // Inside closure: [modify] [static] + doBlockInout({ _ = x }, &x) +} + +// CHECK-LABEL: sil hidden @_T027access_enforcement_noescape19readBlockWriteInoutyyF : $@convention(thin) () -> () { +// CHECK: [[F1:%.*]] = function_ref @_T027access_enforcement_noescape19readBlockWriteInoutyyFyycfU_ : $@convention(thin) (@inout_aliasable Int) -> () +// CHECK: [[PA:%.*]] = partial_apply [[F1]](%0) : $@convention(thin) (@inout_aliasable Int) -> () +// CHECK-NOT: begin_access +// CHECK: [[WRITE:%.*]] = begin_access [modify] [static] %0 : $*Int +// CHECK: apply +// CHECK: end_access [[WRITE]] : $*Int +// CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape19readBlockWriteInoutyyF' + +// CHECK-LABEL: sil private @_T027access_enforcement_noescape19readBlockWriteInoutyyFyycfU_ : $@convention(thin) (@inout_aliasable Int) -> () { +// CHECK: begin_access [read] [static] %0 : $*Int +// CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape19readBlockWriteInoutyyFyycfU_' + +// Test AccessSummaryAnalysis. +// +// The captured @inout_aliasable argument to `doOne` is re-partially applied, +// then stored is a box before passing it to doBlockInout. +func noEscapeBlock() { + var x = 3 + doOne { + doBlockInout({ _ = x }, &x) + } +} +// CHECK-LABEL: sil hidden @_T027access_enforcement_noescape13noEscapeBlockyyF : $@convention(thin) () -> () { +// CHECK: partial_apply +// CHECK-NOT: begin_access +// CHECK: apply +// CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape13noEscapeBlockyyF' + +// CHECK-LABEL: sil private @_T027access_enforcement_noescape13noEscapeBlockyyFyycfU_ : $@convention(thin) (@inout_aliasable Int) -> () { +// CHECK: [[F1:%.*]] = function_ref @_T027access_enforcement_noescape13noEscapeBlockyyFyycfU_yycfU_ : $@convention(thin) (@inout_aliasable Int) -> () +// CHECK: [[PA:%.*]] = partial_apply [[F1]](%0) : $@convention(thin) (@inout_aliasable Int) -> () +// CHECK: [[STORAGE:%.*]] = alloc_stack $@block_storage @callee_owned () -> () +// CHECK: [[ADDR:%.*]] = project_block_storage %5 : $*@block_storage @callee_owned () -> () +// CHECK: store [[PA]] to [[ADDR]] : $*@callee_owned () -> () +// CHECK: [[BLOCK:%.*]] = init_block_storage_header [[STORAGE]] : $*@block_storage @callee_owned () -> (), invoke %8 : $@convention(c) (@inout_aliasable @block_storage @callee_owned () -> ()) -> (), type $@convention(block) () -> () +// CHECK: [[ARG:%.*]] = copy_block [[BLOCK]] : $@convention(block) () -> () +// CHECK: [[WRITE:%.*]] = begin_access [modify] [static] %0 : $*Int +// CHECK: apply %{{.*}}([[ARG]], [[WRITE]]) : $@convention(thin) (@owned @convention(block) () -> (), @inout Int) -> () +// CHECK: end_access [[WRITE]] : $*Int +// CHECK: dealloc_stack [[STORAGE]] : $*@block_storage @callee_owned () -> () +// CHECK: strong_release [[PA]] : $@callee_owned () -> () +// CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape13noEscapeBlockyyFyycfU_' + +// CHECK-LABEL: sil private @_T027access_enforcement_noescape13noEscapeBlockyyFyycfU_yycfU_ : $@convention(thin) (@inout_aliasable Int) -> () { +// CHECK: begin_access [read] [static] %0 : $*Int +// CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape13noEscapeBlockyyFyycfU_yycfU_' diff --git a/test/SILOptimizer/access_enforcement_selection.sil b/test/SILOptimizer/access_enforcement_selection.sil index 07dec6df320..abb60254f87 100644 --- a/test/SILOptimizer/access_enforcement_selection.sil +++ b/test/SILOptimizer/access_enforcement_selection.sil @@ -134,3 +134,49 @@ sil hidden @copyBox : $@convention(thin) () -> () { %98 = tuple () %99 = return %98 : $() } + +sil @closure : $@convention(thin) (@owned { var Builtin.Int64 }) -> () { +bb0(%0 : ${var Builtin.Int64}): + %empty = tuple () + return %empty : $() +} + +// An access that escapes on an unreachable path must be dynamic. +// +// CHECK-LABEL: sil @partialUnreachable : $@convention(thin) () -> () { +// CHECK: %[[ACCESS:.*]] = begin_access [modify] [dynamic] %{{.*}} : $*Builtin.Int64 +// CHECK: bb1: +// CHECK: end_access %[[ACCESS]] : $*Builtin.Int64 +// CHECK: return +// CHECK: bb2: +// CHECK: partial_apply +// CHECK: unreachable +sil @partialUnreachable : $@convention(thin) () -> () { +bb0: + %box = alloc_box ${ var Builtin.Int64 }, var, name "x" + %addr = project_box %box : ${ var Builtin.Int64 }, 0 + %write = begin_access [modify] [unknown] %addr : $*Builtin.Int64 + cond_br undef, bb1, bb2 + +bb1: + end_access %write : $*Builtin.Int64 + %empty = tuple () + return %empty : $() + +bb2: + %f = function_ref @closure : $@convention(thin) (@owned { var Builtin.Int64 }) -> () + %closure = partial_apply %f(%box) : $@convention(thin) (@owned { var Builtin.Int64 }) -> () + unreachable +} + +// An access that refers to mark_uninitialized. +// +// CHECK-LABEL: sil @markUninitSource : $@convention(thin) () -> () { +sil @markUninitSource : $@convention(thin) () -> () { +bb0: + %stk = alloc_stack $Builtin.Int64, let, name "x" + %var = mark_uninitialized [var] %stk : $*Builtin.Int64 + %f = function_ref @closureCapturingByStorageAddress : $@convention(thin) (@inout_aliasable Builtin.Int64) -> () + %closure = partial_apply %f(%var) : $@convention(thin) (@inout_aliasable Builtin.Int64) -> () + unreachable +} diff --git a/test/SILOptimizer/access_marker_selection.sil b/test/SILOptimizer/access_marker_selection.sil deleted file mode 100644 index 0c0d11d962a..00000000000 --- a/test/SILOptimizer/access_marker_selection.sil +++ /dev/null @@ -1,40 +0,0 @@ -// RUN: %target-sil-opt -enable-sil-verify-all %s -access-enforcement-selection -enforce-exclusivity=checked | %FileCheck %s - -sil_stage raw - -import Builtin -import Swift - -sil @closure : $@convention(thin) (@owned { var Builtin.Int64 }) -> () { -bb0(%0 : ${var Builtin.Int64}): - %empty = tuple () - return %empty : $() -} - -// An access that escapes on an unreachable path must be dynamic. -// -// CHECK-LABEL: sil @partialUnreachable : $@convention(thin) () -> () { -// CHECK: %[[ACCESS:.*]] = begin_access [modify] [dynamic] %{{.*}} : $*Builtin.Int64 -// CHECK: bb1: -// CHECK: end_access %[[ACCESS]] : $*Builtin.Int64 -// CHECK: return -// CHECK: bb2: -// CHECK: partial_apply -// CHECK: unreachable -sil @partialUnreachable : $@convention(thin) () -> () { -bb0: - %box = alloc_box ${ var Builtin.Int64 }, var, name "x" - %addr = project_box %box : ${ var Builtin.Int64 }, 0 - %write = begin_access [modify] [unknown] %addr : $*Builtin.Int64 - cond_br undef, bb1, bb2 - -bb1: - end_access %write : $*Builtin.Int64 - %empty = tuple () - return %empty : $() - -bb2: - %f = function_ref @closure : $@convention(thin) (@owned { var Builtin.Int64 }) -> () - %closure = partial_apply %f(%box) : $@convention(thin) (@owned { var Builtin.Int64 }) -> () - unreachable -} diff --git a/test/SILOptimizer/access_summary_analysis.sil b/test/SILOptimizer/access_summary_analysis.sil index 45888371945..b07a5ebbc59 100644 --- a/test/SILOptimizer/access_summary_analysis.sil +++ b/test/SILOptimizer/access_summary_analysis.sil @@ -200,6 +200,59 @@ bb0(%0 : $*Int, %1 : $*Int, %2 : $*Int): return %8 : $() } + +sil @takesAutoClosureReturningGeneric : $@convention(thin) (@owned @callee_owned () -> (@out T, @error Error)) -> () +sil @thunkForAutoClosure : $@convention(thin) (@owned @callee_owned () -> (Int, @error Error)) -> (@out Int, @error Error) + +// CHECK-LABEL: @readsAndThrows +// CHECK-NEXT: (read) +sil private @readsAndThrows : $@convention(thin) (@inout_aliasable Int) -> (Int, @error Error) { +bb0(%0 : $*Int): + %3 = begin_access [read] [unknown] %0 : $*Int + %4 = load %3 : $*Int + end_access %3 : $*Int + return %4 : $Int +} + +// CHECK-LABEL: @passPartialApplyAsArgumentToPartialApply +// CHECK-NEXT: (read) +sil hidden @passPartialApplyAsArgumentToPartialApply : $@convention(thin) (@inout_aliasable Int) -> () { +bb0(%0 : $*Int): + %2 = function_ref @takesAutoClosureReturningGeneric : $@convention(thin) <τ_0_0 where τ_0_0 : Equatable> (@owned @callee_owned () -> (@out τ_0_0, @error Error)) -> () + %3 = function_ref @readsAndThrows : $@convention(thin) (@inout_aliasable Int) -> (Int, @error Error) + %4 = partial_apply %3(%0) : $@convention(thin) (@inout_aliasable Int) -> (Int, @error Error) + %5 = function_ref @thunkForAutoClosure : $@convention(thin) (@owned @callee_owned () -> (Int, @error Error)) -> (@out Int, @error Error) + %6 = partial_apply %5(%4) : $@convention(thin) (@owned @callee_owned () -> (Int, @error Error)) -> (@out Int, @error Error) + %7 = apply %2(%6) : $@convention(thin) <τ_0_0 where τ_0_0 : Equatable> (@owned @callee_owned () -> (@out τ_0_0, @error Error)) -> () + %8 = tuple () + return %8 : $() +} + +// CHECK-LABEL: @reads +// CHECK-NEXT: (read) +sil private @reads : $@convention(thin) (@inout_aliasable Int) -> Int { +bb0(%0 : $*Int): + %3 = begin_access [read] [unknown] %0 : $*Int + %4 = load %3 : $*Int + end_access %3 : $*Int + return %4 : $Int +} + +// CHECK-LABEL: @convertPartialApplyAndPassToPartialApply +// CHECK-NEXT: (read) +sil hidden @convertPartialApplyAndPassToPartialApply : $@convention(thin) (@inout_aliasable Int) -> () { +bb0(%0 : $*Int): + %2 = function_ref @takesAutoClosureReturningGeneric : $@convention(thin) <τ_0_0 where τ_0_0 : Equatable> (@owned @callee_owned () -> (@out τ_0_0, @error Error)) -> () + %3 = function_ref @reads : $@convention(thin) (@inout_aliasable Int) -> Int + %4 = partial_apply %3(%0) : $@convention(thin) (@inout_aliasable Int) -> Int + %5 = convert_function %4 : $@callee_owned () -> Int to $@callee_owned () -> (Int, @error Error) + %6 = function_ref @thunkForAutoClosure : $@convention(thin) (@owned @callee_owned () -> (Int, @error Error)) -> (@out Int, @error Error) + %7 = partial_apply %6(%5) : $@convention(thin) (@owned @callee_owned () -> (Int, @error Error)) -> (@out Int, @error Error) + %8 = apply %2(%7) : $@convention(thin) <τ_0_0 where τ_0_0 : Equatable> (@owned @callee_owned () -> (@out τ_0_0, @error Error)) -> () + %9 = tuple () + return %9 : $() +} + // CHECK-LABEL: @selfRecursion // CHECK-NEXT: (modify, none) sil private @selfRecursion : $@convention(thin) (@inout_aliasable Int, Int) -> () { diff --git a/test/SILOptimizer/array_contentof_opt.swift b/test/SILOptimizer/array_contentof_opt.swift index b5b5c391d98..60dc9592432 100644 --- a/test/SILOptimizer/array_contentof_opt.swift +++ b/test/SILOptimizer/array_contentof_opt.swift @@ -53,3 +53,7 @@ public func testString(_ a: inout [String], s: String) { a += [s] } +// This is not supported yet. Just check that we don't crash on this.` +public func dontPropagateContiguousArray(_ a: inout ContiguousArray) { + a += [4] +} diff --git a/test/SILOptimizer/cast_folding.swift b/test/SILOptimizer/cast_folding.swift index daa86f2480d..4305260ca44 100644 --- a/test/SILOptimizer/cast_folding.swift +++ b/test/SILOptimizer/cast_folding.swift @@ -7,6 +7,7 @@ // which returns either true or false, i.e. all type checks should folded statically. public protocol P {} +public protocol R {} protocol Q: P {} @@ -950,6 +951,87 @@ public func test42(_ p: P) -> Bool { return cast42(p) } +// CHECK-LABEL: sil [noinline] @{{.*}}test43{{.*}} +// CHECK: bb0 +// CHECK-NEXT: %0 = integer_literal $Builtin.Int1, -1 +// CHECK-NEXT: %1 = struct $Bool +// CHECK-NEXT: return %1 +@inline(never) +public func test43() -> Bool { + return P.self is Any.Type +} + +// CHECK-LABEL: sil [noinline] @{{.*}}test44{{.*}} +// CHECK: bb0 +// CHECK-NEXT: %0 = integer_literal $Builtin.Int1, -1 +// CHECK-NEXT: %1 = struct $Bool +// CHECK-NEXT: return %1 +@inline(never) +public func test44() -> Bool { + return Any.self is Any.Type +} + +// CHECK-LABEL: sil [noinline] @{{.*}}test45{{.*}} +// CHECK: bb0 +// CHECK-NEXT: %0 = integer_literal $Builtin.Int1, -1 +// CHECK-NEXT: %1 = struct $Bool +// CHECK-NEXT: return %1 +@inline(never) +public func test45() -> Bool { + return (P & R).self is Any.Type +} + +// CHECK-LABEL: sil [noinline] @{{.*}}test46{{.*}} +// CHECK: bb0 +// CHECK-NEXT: %0 = integer_literal $Builtin.Int1, -1 +// CHECK-NEXT: %1 = struct $Bool +// CHECK-NEXT: return %1 +@inline(never) +public func test46() -> Bool { + return AnyObject.self is Any.Type +} + +// CHECK-LABEL: sil [noinline] @{{.*}}test47{{.*}} +// CHECK: bb0 +// CHECK-NEXT: %0 = integer_literal $Builtin.Int1, -1 +// CHECK-NEXT: %1 = struct $Bool +// CHECK-NEXT: return %1 +@inline(never) +public func test47() -> Bool { + return Any.Type.self is Any.Type +} + +// CHECK-LABEL: sil [noinline] @{{.*}}test48{{.*}} +// CHECK: bb0 +// CHECK-NEXT: %0 = integer_literal $Builtin.Int1, 0 +// CHECK-NEXT: %1 = struct $Bool +// CHECK-NEXT: return %1 +@inline(never) +public func test48() -> Bool { + return Any.Type.self is Any.Type.Type +} + +func cast(_ u: U.Type) -> V? { + return u as? V +} + +// CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyObjectProtocolTo{{.*}}Type +// CHECK: %0 = enum $Optional{{.*}}, #Optional.none!enumelt +// CHECK-NEXT: return %0 +@inline(never) +public func testCastAnyObjectProtocolToAnyObjectType() -> AnyObject.Type? { + return cast(AnyObject.self) +} + +// CHECK-LABEL: // testCastProtocolTypeProtocolToProtocolTypeType +// CHECK: sil [noinline] @{{.*}}testCastProtocol{{.*}}$@convention(thin) () -> Optional<@thick P.Type.Type> +// CHECK: %0 = enum $Optional{{.*}}, #Optional.none!enumelt +// CHECK-NEXT: return %0 +@inline(never) +public func testCastProtocolTypeProtocolToProtocolTypeType() -> P.Type.Type? { + return P.Type.self as? P.Type.Type +} + print("test0=\(test0())") print("test1=\(test1())") diff --git a/test/SILOptimizer/cast_folding_objc.swift b/test/SILOptimizer/cast_folding_objc.swift index 5f268c6b1a3..8f9819817df 100644 --- a/test/SILOptimizer/cast_folding_objc.swift +++ b/test/SILOptimizer/cast_folding_objc.swift @@ -196,6 +196,38 @@ public func testCastEveryToNonClassType(_ o: T) -> Int.Type { return o as! Int.Type } +func cast(_ u: U.Type) -> V? { + return u as? V +} + +public protocol P { +} + +// Any casts from P.Protocol to P.Type should fail. +@inline(never) +public func testCastPProtocolToPType() -> ObjCP.Type? { + return cast(ObjCP.self) +} + +@objc +public protocol ObjCP { +} + +@inline(never) +public func testCastObjCPProtocolToObjCPType() -> ObjCP.Type? { + return cast(ObjCP.self) +} + +@inline(never) +public func testCastProtocolCompositionProtocolToProtocolCompositionType() -> (P & ObjCP).Type? { + return cast((P & ObjCP).self) +} + +@inline(never) +public func testCastProtocolCompositionProtocolToProtocolType () -> P.Type? { + return (P & ObjCP).self as? P.Type +} + print("test0=\(test0())") @@ -241,7 +273,17 @@ print("test0=\(test0())") // CHECK-LABEL: sil [noinline] @{{.*}}testCastEveryToNonClassType // CHECK: unconditional_checked_cast_addr +// CHECK-LABEL: sil [noinline] @{{.*}}testCastPProtocolToPType +// CHECK: %0 = enum $Optional{{.*}}, #Optional.none!enumelt +// CHECK-NEXT: return %0 +// CHECK-LABEL: sil [noinline] @{{.*}}testCastObjCPProtocolTo{{.*}}PType +// CHECK: %0 = enum $Optional{{.*}}, #Optional.none!enumelt +// CHECK-NEXT: return %0 + +// CHECK-LABEL: sil [noinline] @{{.*}}testCastProtocolComposition{{.*}}Type +// CHECK: %0 = enum $Optional{{.*}}, #Optional.none!enumelt +// CHECK-NEXT: return %0 // Check that compiler understands that this cast always succeeds. // Since it is can be statically proven that NSString is bridgeable to String, diff --git a/test/SILOptimizer/copyforward.sil b/test/SILOptimizer/copyforward.sil index 1abbdd7159c..cf696013cb1 100644 --- a/test/SILOptimizer/copyforward.sil +++ b/test/SILOptimizer/copyforward.sil @@ -450,7 +450,7 @@ bb0: // CHECK-LABEL: sil @nil_comparison // CHECK: alloc_stack // CHECK-NOT: copy_addr -// CHECK-NOT destroy_addr +// CHECK-NOT: destroy_addr // CHECK: switch_enum_addr %0 // CHECK: [[D:%.*]] = unchecked_take_enum_data_addr %0 // CHECK: destroy_addr [[D]] diff --git a/test/SILOptimizer/dead_function_elimination.swift b/test/SILOptimizer/dead_function_elimination.swift index 66882b0391f..870e5e45af6 100644 --- a/test/SILOptimizer/dead_function_elimination.swift +++ b/test/SILOptimizer/dead_function_elimination.swift @@ -1,5 +1,5 @@ -// RUN: %target-swift-frontend %s -O -emit-sil | %FileCheck %s -// RUN: %target-swift-frontend %s -O -emit-sil -enable-testing | %FileCheck -check-prefix=CHECK-TESTING %s +// RUN: %target-swift-frontend %s -O -emit-sil -sil-serialize-witness-tables | %FileCheck %s +// RUN: %target-swift-frontend %s -O -emit-sil -sil-serialize-witness-tables -enable-testing | %FileCheck -check-prefix=CHECK-TESTING %s // Check if cycles are removed. diff --git a/test/SILOptimizer/dead_store_elim.sil b/test/SILOptimizer/dead_store_elim.sil index af7dcae586d..fc723664555 100644 --- a/test/SILOptimizer/dead_store_elim.sil +++ b/test/SILOptimizer/dead_store_elim.sil @@ -1038,7 +1038,7 @@ bb0(%0 : $*Example): /// Make sure we can coalesce the 2 live stores to the 2 fields in S4. /// -/// CHECK-LABEL : partial_dead_store_struct_in_struct +/// CHECK-LABEL: partial_dead_store_struct_in_struct /// CHECK: [[RET0:%.+]] = struct_extract /// CHECK: [[RET1:%.+]] = struct_element_addr /// CHECK: {{ store}} [[RET0:%.+]] to [[RET1:%.+]] : $*S4 @@ -1058,7 +1058,7 @@ bb0(%0 : $*S5): /// Make sure we do not coalesce the 2 live stores to the 2 fields in S6. /// -/// CHECK-LABEL : sil hidden @discontiguous_partial_dead_store_simple_struct +/// CHECK-LABEL: sil hidden @discontiguous_partial_dead_store_simple_struct /// CHECK: store /// CHECK: store sil hidden @discontiguous_partial_dead_store_simple_struct : $@convention(thin) (@inout S6) -> () { @@ -1077,7 +1077,7 @@ bb0(%0 : $*S6): /// Make sure we generate the store to field x first. /// -/// CHECK-LABEL : sil hidden @discontiguous_partial_dead_store_lives_insert_deterministically +/// CHECK-LABEL: sil hidden @discontiguous_partial_dead_store_lives_insert_deterministically /// CHECK: bb0([[A:%.*]] : $*S6): /// CHECK: [[IN:%.*]] = apply /// CHECK: [[EXT1:%.*]] = struct_extract [[IN]] : $S6, #S6.x @@ -1121,7 +1121,7 @@ bb0(%0 : $*S7): /// i.e. too many stores generated, but make sure we track the store correctly /// so that we can get rid of store %56 to %57 : $*Int. /// -/// CHECK-LABEL : partial_dead_store_bail_out_proper_propagation +/// CHECK-LABEL: partial_dead_store_bail_out_proper_propagation /// CHECK: bb0 /// CHECK-NOT: {{ store}} /// CHECK: function_ref diff --git a/test/SILOptimizer/devirt_materializeForSet.swift b/test/SILOptimizer/devirt_materializeForSet.swift index 12fdf59f9c9..fb6742c37f7 100644 --- a/test/SILOptimizer/devirt_materializeForSet.swift +++ b/test/SILOptimizer/devirt_materializeForSet.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -O -emit-sil %s | %FileCheck %s +// RUN: %target-swift-frontend -O -emit-sil -sil-serialize-witness-tables %s | %FileCheck %s // Check that compiler does not crash on the devirtualization of materializeForSet methods // and produces a correct code. diff --git a/test/SILOptimizer/earlycodemotion.sil b/test/SILOptimizer/earlycodemotion.sil index dbb07d75c00..b4163dd8bdc 100644 --- a/test/SILOptimizer/earlycodemotion.sil +++ b/test/SILOptimizer/earlycodemotion.sil @@ -1341,7 +1341,7 @@ bb1: // Preds: bb0 // Make sure we were able to sink the release. // CHECK: strong_release // CHECK-NEXT: tuple () -// CHECK-NEXT return +// CHECK-NEXT: return bb2: // Preds: bb4 bb5 %5 = tuple () // user: %6 diff --git a/test/SILOptimizer/exclusivity_static_diagnostics.sil b/test/SILOptimizer/exclusivity_static_diagnostics.sil index df804540e80..118b23dc01f 100644 --- a/test/SILOptimizer/exclusivity_static_diagnostics.sil +++ b/test/SILOptimizer/exclusivity_static_diagnostics.sil @@ -9,6 +9,8 @@ import Swift sil @takesTwoInouts : $@convention(thin) (@inout Int, @inout Int) -> () sil @takesOneInout : $@convention(thin) (@inout Int) -> () sil @makesInt : $@convention(thin) () -> Int +sil @takesInoutAndNoEscapeClosure : $@convention(thin) (@inout Int, @owned @callee_owned () -> ()) -> () +sil @takesInoutAndNoEscapeClosureTakingArgument : $@convention(thin) (@inout Int, @owned @callee_owned (Int) -> ()) -> () // CHECK-LABEL: sil hidden @twoLocalInoutsDisaliased sil hidden @twoLocalInoutsDisaliased : $@convention(thin) (Int) -> () { @@ -546,6 +548,82 @@ bb0(%0 : $Storage, %1 : $Builtin.Word): return %8 : $Int } +// Conflicts involving noescape closures. + +sil hidden @closureThatModifiesCapture_1: $@convention(thin) (@inout_aliasable Int) -> () { +bb0(%0 : $*Int): + %1 = begin_access [modify] [unknown] %0 : $*Int // expected-note {{conflicting access is here}} + end_access %1 : $*Int + %2 = tuple () + return %2 : $() +} + +// CHECK-LABEL: sil hidden @inProgressModifyModifyConflictWithCallToClosure +sil hidden @inProgressModifyModifyConflictWithCallToClosure : $@convention(thin) (Int) -> () { +bb0(%0 : $Int): + %2 = alloc_box ${ var Int } + %3 = project_box %2 : ${ var Int }, 0 + store %0 to [trivial] %3 : $*Int + %4 = function_ref @closureThatModifiesCapture_1: $@convention(thin) (@inout_aliasable Int) -> () + %5 = begin_access [modify] [unknown] %3 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}} + %8 = apply %4(%3) : $@convention(thin) (@inout_aliasable Int) -> () + end_access %5: $*Int + destroy_value %2 : ${ var Int } + %9 = tuple () + return %9 : $() +} + + +sil hidden @closureWithArgument_1 : $@convention(thin) (Int, @inout_aliasable Int) -> () { +bb0(%0 : $Int, %1 : $*Int): + %2 = begin_access [modify] [unknown] %1 : $*Int // expected-note {{conflicting access is here}} + end_access %2 : $*Int + %3 = tuple () + return %3 : $() +} + +// CHECK-LABEL: sil hidden @inProgressConflictWithNoEscapeClosureArgument +sil hidden @inProgressConflictWithNoEscapeClosureArgument : $@convention(thin) (Int) -> () { +bb0(%0 : $Int): + %2 = alloc_box ${ var Int } + %3 = project_box %2 : ${ var Int }, 0 + store %0 to [trivial] %3 : $*Int + %4 = function_ref @takesInoutAndNoEscapeClosureTakingArgument : $@convention(thin) (@inout Int, @owned @callee_owned (Int) -> ()) -> () + %5 = function_ref @closureWithArgument_1 : $@convention(thin) (Int, @inout_aliasable Int) -> () + %6 = partial_apply %5(%3) : $@convention(thin) (Int, @inout_aliasable Int) -> () + %7 = begin_access [modify] [unknown] %3 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}} + %8 = apply %4(%3, %6) : $@convention(thin) (@inout Int, @owned @callee_owned (Int) -> ()) -> () + end_access %7: $*Int + destroy_value %2 : ${ var Int } + %9 = tuple () + return %9 : $() +} + +sil hidden @closureThatModifiesCapture_2 : $@convention(thin) (@inout_aliasable Int) -> () { +bb0(%0 : $*Int): + %1 = begin_access [modify] [unknown] %0 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}} + end_access %1 : $*Int + %2 = tuple () + return %2 : $() +} + +// CHECK-LABEL: sil hidden @inProgressReadModifyConflictWithNoEscapeClosureArgument +sil hidden @inProgressReadModifyConflictWithNoEscapeClosureArgument : $@convention(thin) (Int) -> () { +bb0(%0 : $Int): + %2 = alloc_box ${ var Int } + %3 = project_box %2 : ${ var Int }, 0 + store %0 to [trivial] %3 : $*Int + %4 = function_ref @takesInoutAndNoEscapeClosure : $@convention(thin) (@inout Int, @owned @callee_owned () -> ()) -> () + %5 = function_ref @closureThatModifiesCapture_2 : $@convention(thin) (@inout_aliasable Int) -> () + %6 = partial_apply %5(%3) : $@convention(thin) (@inout_aliasable Int) -> () + %7 = begin_access [read] [unknown] %3 : $*Int // expected-note {{conflicting access is here}} + %8 = apply %4(%3, %6) : $@convention(thin) (@inout Int, @owned @callee_owned () -> ()) -> () + end_access %7: $*Int + destroy_value %2 : ${ var Int } + %9 = tuple () + return %9 : $() +} + // Stored property relaxation. struct NestedStructWithStoredProps { diff --git a/test/SILOptimizer/exclusivity_static_diagnostics.swift b/test/SILOptimizer/exclusivity_static_diagnostics.swift index 4be7db8b4f8..97e3e25f635 100644 --- a/test/SILOptimizer/exclusivity_static_diagnostics.swift +++ b/test/SILOptimizer/exclusivity_static_diagnostics.swift @@ -183,6 +183,90 @@ struct StructWithFixits { } } +func takesInoutAndNoEscapeClosure(_ p: inout T, _ c: () -> ()) { } + +func callsTakesInoutAndNoEscapeClosure() { + var local = 5 + takesInoutAndNoEscapeClosure(&local) { // expected-error {{overlapping accesses to 'local', but modification requires exclusive access; consider copying to a local variable}} + local = 8 // expected-note {{conflicting access is here}} + } +} + +func takesInoutAndNoEscapeClosureThatThrows(_ p: inout T, _ c: () throws -> ()) { } + +func callsTakesInoutAndNoEscapeClosureThatThrowsWithNonThrowingClosure() { + var local = 5 + takesInoutAndNoEscapeClosureThatThrows(&local) { // expected-error {{overlapping accesses to 'local', but modification requires exclusive access; consider copying to a local variable}} + local = 8 // expected-note {{conflicting access is here}} + } +} + +func takesInoutAndNoEscapeClosureAndThrows(_ p: inout T, _ c: () -> ()) throws { } + +func callsTakesInoutAndNoEscapeClosureAndThrows() { + var local = 5 + try! takesInoutAndNoEscapeClosureAndThrows(&local) { // expected-error {{overlapping accesses to 'local', but modification requires exclusive access; consider copying to a local variable}} + local = 8 // expected-note {{conflicting access is here}} + } +} + +func takesTwoNoEscapeClosures(_ c1: () -> (), _ c2: () -> ()) { } + +func callsTakesTwoNoEscapeClosures() { + var local = 7 + takesTwoNoEscapeClosures({local = 8}, {local = 9}) // no-error + _ = local +} + +func takesInoutAndEscapingClosure(_ p: inout T, _ c: @escaping () -> ()) { } + +func callsTakesInoutAndEscapingClosure() { + var local = 5 + takesInoutAndEscapingClosure(&local) { // no-error + local = 8 + } +} + +func takesUnsafePointerAndNoEscapeClosure(_ p: UnsafePointer, _ c: () -> ()) { } + +func callsTakesUnsafePointerAndNoEscapeClosure() { + var local = 1 + takesUnsafePointerAndNoEscapeClosure(&local) { // expected-note {{conflicting access is here}} + local = 2 // expected-error {{overlapping accesses to 'local', but modification requires exclusive access; consider copying to a local variable}} + } +} + +func takesThrowingAutoClosureReturningGeneric(_ : @autoclosure () throws -> T) { } +func takesInoutAndClosure(_: inout Int, _ : () -> ()) { } + +func callsTakesThrowingAutoClosureReturningGeneric() { + var i = 0 + takesInoutAndClosure(&i) { // expected-error {{overlapping accesses to 'i', but modification requires exclusive access; consider copying to a local variable}} + takesThrowingAutoClosureReturningGeneric(i) // expected-note {{conflicting access is here}} + } +} + +struct StructWithMutatingMethodThatTakesAutoclosure { + var f = 2 + mutating func takesAutoclosure(_ p: @autoclosure () throws -> ()) rethrows { } +} + +func conflictOnSubPathInNoEscapeAutoclosure() { + var s = StructWithMutatingMethodThatTakesAutoclosure() + s.takesAutoclosure(s.f = 2) + // expected-error@-1 {{overlapping accesses to 's', but modification requires exclusive access; consider copying to a local variable}} + // expected-note@-2 {{conflicting access is here}} +} + +func conflictOnWholeInNoEscapeAutoclosure() { + var s = StructWithMutatingMethodThatTakesAutoclosure() + takesInoutAndNoEscapeClosure(&s.f) { + // expected-error@-1 {{overlapping accesses to 's.f', but modification requires exclusive access; consider copying to a local variable}} + s = StructWithMutatingMethodThatTakesAutoclosure() + // expected-note@-1 {{conflicting access is here}} + } +} + func inoutSeparateStructStoredProperties() { var s = StructWithTwoStoredProp() takesTwoInouts(&s.f1, &s.f2) // no-error @@ -220,3 +304,12 @@ func inoutSamePropertyInSameTuple() { // expected-error@-1{{overlapping accesses to 't.name2.f1', but modification requires exclusive access; consider copying to a local variable}} // expected-note@-2{{conflicting access is here}} } + +struct MyStruct { + var prop = 7 + mutating func inoutBoundGenericStruct() { + takesTwoInouts(&prop, &prop) + // expected-error@-1{{overlapping accesses to 'self.prop', but modification requires exclusive access; consider copying to a local variable}} + // expected-note@-2{{conflicting access is here}} + } +} diff --git a/test/SILOptimizer/functionsigopts.sil b/test/SILOptimizer/functionsigopts.sil index 82b6c14e25e..b2405c7d7c1 100644 --- a/test/SILOptimizer/functionsigopts.sil +++ b/test/SILOptimizer/functionsigopts.sil @@ -511,7 +511,7 @@ bb0(%0 : $boo): // CHECK-LABEL: sil [serialized] [thunk] [always_inline] @owned_to_unowned_retval_with_error_result : $@convention(thin) (@owned boo) -> (@owned boo, @error Error) { // CHECK: function_ref @_T041owned_to_unowned_retval_with_error_resultTfq4n_g : $@convention(thin) (@owned boo) -> (boo, @error Error) // CHECK: bb1 -// CHECK-NOT retain_value +// CHECK-NOT: retain_value // CHECK: bb2 sil [serialized] @owned_to_unowned_retval_with_error_result : $@convention(thin) (@owned boo) -> (@owned boo, @error Error) { bb0(%0 : $boo): diff --git a/test/SILOptimizer/inline_cache_and_arc.swift b/test/SILOptimizer/inline_cache_and_arc.swift new file mode 100644 index 00000000000..0601f304660 --- /dev/null +++ b/test/SILOptimizer/inline_cache_and_arc.swift @@ -0,0 +1,38 @@ +// RUN: %target-swift-frontend -parse-as-library -O -emit-sil %s | %FileCheck %s +// REQUIRES: swift_stdlib_no_asserts,optimized_stdlib,CPU=x86_64 + +// Test inline cache with a global class. Make sure the retain|release pair +// for the fast path is removed in the loop. + +open class A +{ + open func f(_ a: Int) -> Int + { + return a + 1 + } +} + +var x = 0 +public var a = A() + +public func testit() { +// CHECK-LABEL: sil @{{.*}}testityyF +// CHECK: bb0: +// CHECK-NOT: {{.*(retain|release).*}} +// CHECK: checked_cast_br +// CHECK: bb1{{.*}}: +// CHECK-NOT: {{.*(retain|release).*}} +// CHECK: return +// CHECK: bb2{{.*}}: +// CHECK-NOT: {{.*(retain|release|apply).*}} +// CHECK: br bb1 +// CHECK: bb3{{.*}}: +// CHECK-NEXT: class_method +// CHECK-NEXT: strong_retain +// CHECK-NEXT: apply +// CHECK-NEXT: strong_release +// CHECK-NEXT: br bb1 + + x = a.f(x) +} + diff --git a/test/SILOptimizer/inout_capture_diagnostics.swift b/test/SILOptimizer/inout_capture_diagnostics.swift new file mode 100644 index 00000000000..1d91dc07d9a --- /dev/null +++ b/test/SILOptimizer/inout_capture_diagnostics.swift @@ -0,0 +1,28 @@ +// RUN: %target-swift-frontend -enforce-exclusivity=checked -Onone -emit-sil -swift-version 4 -verify -parse-as-library %s +// +// This is an adjunct to access_enforcement_noescape.swift to cover early static diagnostics. + +// Helper +func doOneInout(_: ()->(), _: inout Int) {} + +// Error: Cannot capture nonescaping closure. +// expected-note@+1{{parameter 'fn' is implicitly non-escaping}} +func reentrantCapturedNoescape(fn: (() -> ()) -> ()) { + // expected-error@+1{{closure use of non-escaping parameter 'fn' may allow it to escape}} + let c = { fn {} } + fn(c) +} + +// Error: inout cannot be captured. +func inoutReadBoxWriteInout(x: inout Int) { + // expected-error@+1{{escaping closures can only capture inout parameters explicitly by value}} + let c = { _ = x } + doOneInout(c, &x) +} + +// Error: Cannot capture inout +func inoutWriteBoxWriteInout(x: inout Int) { + // expected-error@+1{{escaping closures can only capture inout parameters explicitly by value}} + let c = { x = 42 } + doOneInout(c, &x) +} diff --git a/test/SILOptimizer/mandatory_inlining.swift b/test/SILOptimizer/mandatory_inlining.swift index 39b686994ac..f99fa1b6258 100644 --- a/test/SILOptimizer/mandatory_inlining.swift +++ b/test/SILOptimizer/mandatory_inlining.swift @@ -108,7 +108,7 @@ func test_chained_short_circuit(_ x: Bool, y: Bool, z: Bool) -> Bool { // recursively inlined properly) // CHECK-LABEL: sil hidden @_T018mandatory_inlining26test_chained_short_circuit{{[_0-9a-zA-Z]*}}F - // CHECK-NOT = apply [transparent] + // CHECK-NOT: = apply [transparent] // CHECK: return @@ -122,7 +122,7 @@ func testInlineUnionElement() -> X { return X.onetransp // CHECK-LABEL: sil hidden @_T018mandatory_inlining22testInlineUnionElementAA1XOyF // CHECK: enum $X, #X.onetransp!enumelt - // CHECK-NOT = apply + // CHECK-NOT: = apply // CHECK: return } diff --git a/test/SILOptimizer/retain_release_code_motion.sil b/test/SILOptimizer/retain_release_code_motion.sil index 0fedb71dd3d..6a18d1ae71d 100644 --- a/test/SILOptimizer/retain_release_code_motion.sil +++ b/test/SILOptimizer/retain_release_code_motion.sil @@ -443,3 +443,91 @@ bb3: %5 = tuple() return %5 : $() } + +// CHECK-LABEL: sil @move_retain_over_loop +// CHECK: bb0({{.*}}): +// CHECK-NEXT: br bb1 +// CHECK: bb1: +// CHECK-NEXT: cond_br +// CHECK: bb2: +// CHECK: strong_retain +// CHECK: apply +// CHECK: strong_release +// CHECK: return +sil @move_retain_over_loop : $@convention(thin) (Builtin.NativeObject) -> () { +bb0(%0 : $Builtin.NativeObject): + strong_retain %0 : $Builtin.NativeObject + br bb1 + +bb1: + cond_br undef, bb1, bb2 + +bb2: + %2 = function_ref @blocker : $@convention(thin) () -> () + apply %2() : $@convention(thin) () -> () + strong_release %0 : $Builtin.NativeObject + %1 = tuple() + return %1 : $() +} + +// CHECK-LABEL: sil @move_release_over_loop +// CHECK: bb0{{.*}}: +// CHECK: strong_retain +// CHECK: apply +// CHECK: strong_release +// CHECK: br bb1 +// CHECK: bb1: +// CHECK-NEXT: cond_br +// CHECK: bb2: +// CHECK-NEXT: br bb1 +// CHECK: bb3: +// CHECK-NEXT: tuple +// CHECK-NEXT: return +sil @move_release_over_loop : $@convention(thin) (Builtin.NativeObject) -> () { +bb0(%0 : $Builtin.NativeObject): + strong_retain %0 : $Builtin.NativeObject + %2 = function_ref @blocker : $@convention(thin) () -> () + apply %2() : $@convention(thin) () -> () + br bb1 + +bb1: + cond_br undef, bb1, bb2 + +bb2: + strong_release %0 : $Builtin.NativeObject + %1 = tuple() + return %1 : $() +} + +// CHECK-LABEL: sil @handle_infinite_loop +// CHECK: bb0{{.*}}: +// CHECK-NEXT: cond_br +// CHECK: bb1: +// CHECK-NOT: {{(retain|release)}} +// CHECK: apply +// CHECK-NEXT: br bb2 +// CHECK: bb2: +// CHECK-NEXT: br bb2 +// CHECK: bb3: +// CHECK: strong_retain +// CHECK: strong_release +// CHECK: return +sil @handle_infinite_loop : $@convention(thin) (@inout Builtin.NativeObject) -> () { +bb0(%a : $*Builtin.NativeObject): + cond_br undef, bb1, bb3 + +bb1: + %2 = function_ref @blocker : $@convention(thin) () -> () + apply %2() : $@convention(thin) () -> () + br bb2 + +bb2: + br bb2 + +bb3: + %0 = load %a : $*Builtin.NativeObject + strong_retain %0 : $Builtin.NativeObject + strong_release %0 : $Builtin.NativeObject + %1 = tuple() + return %1 : $() +} diff --git a/test/Sanitizers/asan.swift b/test/Sanitizers/asan.swift index fdfba2dbce5..055cb4cd286 100644 --- a/test/Sanitizers/asan.swift +++ b/test/Sanitizers/asan.swift @@ -1,9 +1,8 @@ -// RUN: %target-swiftc_driver %s -g -sanitize=address -o %t_tsan-binary -// RUN: not env ASAN_OPTIONS=abort_on_error=0 %target-run %t_tsan-binary 2>&1 | %FileCheck %s +// RUN: %target-swiftc_driver %s -target %sanitizers-target-triple -g -sanitize=address -o %t_asan-binary +// RUN: not env %env-ASAN_OPTIONS=abort_on_error=0 %target-run %t_asan-binary 2>&1 | %FileCheck %s // REQUIRES: executable_test // REQUIRES: objc_interop // REQUIRES: asan_runtime -// XFAIL: linux // Make sure we can handle swifterror. LLVM's address sanitizer pass needs to // ignore swifterror addresses. diff --git a/test/Sanitizers/tsan-ignores-arc-locks.swift b/test/Sanitizers/tsan-ignores-arc-locks.swift index 0299f66ff44..fdc8214f0ab 100644 --- a/test/Sanitizers/tsan-ignores-arc-locks.swift +++ b/test/Sanitizers/tsan-ignores-arc-locks.swift @@ -1,7 +1,6 @@ -// RUN: %target-build-swift -sanitize=thread %s -o %t_binary -// RUN: TSAN_OPTIONS=ignore_interceptors_accesses=1:halt_on_error=1 %t_binary +// RUN: %target-build-swift -target %sanitizers-target-triple -sanitize=thread %s -o %t_binary +// RUN: %env-TSAN_OPTIONS=ignore_interceptors_accesses=1:halt_on_error=1 %target-run %t_binary // REQUIRES: executable_test -// REQUIRES: CPU=x86_64 // REQUIRES: tsan_runtime // REQUIRES: objc_interop diff --git a/test/Sanitizers/tsan-inout.swift b/test/Sanitizers/tsan-inout.swift index 91d0314ea83..495487647d8 100644 --- a/test/Sanitizers/tsan-inout.swift +++ b/test/Sanitizers/tsan-inout.swift @@ -1,13 +1,11 @@ -// RUN: %target-build-swift %S/Inputs/tsan-uninstrumented.swift -module-name TSanUninstrumented -emit-module -emit-module-path %T/TSanUninstrumented.swiftmodule -parse-as-library -// RUN: %target-build-swift %S/Inputs/tsan-uninstrumented.swift -c -module-name TSanUninstrumented -parse-as-library -o %T/TSanUninstrumented.o +// RUN: %target-build-swift %S/Inputs/tsan-uninstrumented.swift -target %sanitizers-target-triple -module-name TSanUninstrumented -emit-module -emit-module-path %T/TSanUninstrumented.swiftmodule -parse-as-library +// RUN: %target-build-swift %S/Inputs/tsan-uninstrumented.swift -target %sanitizers-target-triple -c -module-name TSanUninstrumented -parse-as-library -o %T/TSanUninstrumented.o // RUN: %target-swiftc_driver %s %T/TSanUninstrumented.o -I%T -L%T -g -sanitize=thread -o %t_tsan-binary -// RUN: not env TSAN_OPTIONS=abort_on_error=0 %target-run %t_tsan-binary 2>&1 | %FileCheck %s -// RUN: not env TSAN_OPTIONS=abort_on_error=0:ignore_interceptors_accesses=0 %target-run %t_tsan-binary 2>&1 | %FileCheck %s --check-prefix CHECK-INTERCEPTORS-ACCESSES +// RUN: not env %env-TSAN_OPTIONS=abort_on_error=0 %target-run %t_tsan-binary 2>&1 | %FileCheck %s +// RUN: not env %env-TSAN_OPTIONS=abort_on_error=0:ignore_interceptors_accesses=0 %target-run %t_tsan-binary 2>&1 | %FileCheck %s --check-prefix CHECK-INTERCEPTORS-ACCESSES // REQUIRES: executable_test // REQUIRES: objc_interop -// REQUIRES: CPU=x86_64 // REQUIRES: tsan_runtime -// XFAIL: linux // Test ThreadSanitizer execution end-to-end when calling // an uninstrumented module with inout parameters diff --git a/test/Sanitizers/tsan-norace-block-release.swift b/test/Sanitizers/tsan-norace-block-release.swift index 9f5494e6cbd..534fc82ba7e 100644 --- a/test/Sanitizers/tsan-norace-block-release.swift +++ b/test/Sanitizers/tsan-norace-block-release.swift @@ -1,10 +1,8 @@ -// RUN: %target-swiftc_driver %s -g -sanitize=thread -o %t_tsan-binary -// RUN: env TSAN_OPTIONS=abort_on_error=0:ignore_interceptors_accesses=1 %target-run %t_tsan-binary 2>&1 | %FileCheck %s +// RUN: %target-swiftc_driver %s -g -sanitize=thread -target %sanitizers-target-triple -o %t_tsan-binary +// RUN: env %env-TSAN_OPTIONS=abort_on_error=0:ignore_interceptors_accesses=1 %target-run %t_tsan-binary 2>&1 | %FileCheck %s // REQUIRES: executable_test // REQUIRES: objc_interop -// REQUIRES: CPU=x86_64 // REQUIRES: tsan_runtime -// XFAIL: linux // Test that we do not report a race on block release operation. import Foundation diff --git a/test/Sanitizers/tsan-norace-deinit-run-time.swift b/test/Sanitizers/tsan-norace-deinit-run-time.swift index b718165ba70..6c0f8c05abb 100644 --- a/test/Sanitizers/tsan-norace-deinit-run-time.swift +++ b/test/Sanitizers/tsan-norace-deinit-run-time.swift @@ -1,10 +1,8 @@ -// RUN: %target-swiftc_driver %s -g -sanitize=thread -o %t_tsan-binary -// RUN: env TSAN_OPTIONS=abort_on_error=0:ignore_interceptors_accesses=1 %target-run %t_tsan-binary 2>&1 | %FileCheck %s +// RUN: %target-swiftc_driver %s -g -sanitize=thread -target %sanitizers-target-triple -o %t_tsan-binary +// RUN: env %env-TSAN_OPTIONS=abort_on_error=0:ignore_interceptors_accesses=1 %target-run %t_tsan-binary 2>&1 | %FileCheck %s // REQUIRES: executable_test // REQUIRES: objc_interop -// REQUIRES: CPU=x86_64 // REQUIRES: tsan_runtime -// XFAIL: linux // Test that we do not report a race on deinit; the synchronization is guaranteed by runtime. import Foundation diff --git a/test/Sanitizers/tsan-type-metadata.swift b/test/Sanitizers/tsan-type-metadata.swift index a9c3bde917e..4a4014bc090 100644 --- a/test/Sanitizers/tsan-type-metadata.swift +++ b/test/Sanitizers/tsan-type-metadata.swift @@ -1,9 +1,7 @@ -// RUN: %target-build-swift -sanitize=thread %s -o %t_binary -// RUN: TSAN_OPTIONS=ignore_interceptors_accesses=1:halt_on_error=1 %t_binary +// RUN: %target-swiftc_driver -target %sanitizers-target-triple -sanitize=thread %s -o %t_binary +// RUN: %env-TSAN_OPTIONS=ignore_interceptors_accesses=1:halt_on_error=1 %target-run %t_binary // REQUIRES: executable_test // REQUIRES: objc_interop -// REQUIRES: CPU=x86_64 -// REQUIRES: OS=macosx // REQUIRES: tsan_runtime // We expect not to report any races on this testcase. diff --git a/test/Sanitizers/tsan.swift b/test/Sanitizers/tsan.swift index 2cffe269646..e59e56c9635 100644 --- a/test/Sanitizers/tsan.swift +++ b/test/Sanitizers/tsan.swift @@ -1,10 +1,8 @@ -// RUN: %target-swiftc_driver %s -g -sanitize=thread -o %t_tsan-binary -// RUN: not env TSAN_OPTIONS=abort_on_error=0 %target-run %t_tsan-binary 2>&1 | %FileCheck %s +// RUN: %target-swiftc_driver %s -target %sanitizers-target-triple -g -sanitize=thread -o %t_tsan-binary +// RUN: not env %env-TSAN_OPTIONS="abort_on_error=0" %target-run %t_tsan-binary 2>&1 | %FileCheck %s // REQUIRES: executable_test // REQUIRES: objc_interop -// REQUIRES: CPU=x86_64 // REQUIRES: tsan_runtime -// XFAIL: linux // Make sure we can handle swifterror and don't bail during the LLVM // threadsanitizer pass. diff --git a/test/Sanitizers/witness_table_lookup.swift b/test/Sanitizers/witness_table_lookup.swift index 055cea17374..d9e851accf7 100644 --- a/test/Sanitizers/witness_table_lookup.swift +++ b/test/Sanitizers/witness_table_lookup.swift @@ -1,9 +1,8 @@ -// RUN: %target-build-swift -sanitize=thread %s -o %t_binary -// RUN: TSAN_OPTIONS=ignore_interceptors_accesses=1:halt_on_error=1 %t_binary +// RUN: %target-build-swift -sanitize=thread -target %sanitizers-target-triple %s -o %t_binary +// RUN: %env-TSAN_OPTIONS=ignore_interceptors_accesses=1:halt_on_error=1 %target-run %t_binary // REQUIRES: executable_test -// REQUIRES: CPU=x86_64 -// REQUIRES: OS=macosx // REQUIRES: tsan_runtime +// REQUIRES: objc_interop // Check that TSan does not report spurious races in witness table lookup. diff --git a/test/Sema/accessibility_private.swift b/test/Sema/accessibility_private.swift index 01a4072618f..c78b4b33c10 100644 --- a/test/Sema/accessibility_private.swift +++ b/test/Sema/accessibility_private.swift @@ -163,51 +163,51 @@ extension Container { } } -// All of these should be errors, but didn't have the correct behavior in Swift -// 3.0GM. +// All of these are errors in Swift 4, but didn't have the correct behavior in +// Swift 3.0GM. extension Container { private struct VeryPrivateStruct { // expected-note * {{type declared here}} private typealias VeryPrivateType = Int // expected-note * {{type declared here}} - var privateVar: VeryPrivateType { fatalError() } // expected-warning {{property should be declared private because its type uses a private type}} - var privateVar2 = VeryPrivateType() // expected-warning {{property should be declared private because its type 'Container.VeryPrivateStruct.VeryPrivateType' (aka 'Int') uses a private type}} - typealias PrivateAlias = VeryPrivateType // expected-warning {{type alias should be declared private because its underlying type uses a private type}} - subscript(_: VeryPrivateType) -> Void { return () } // expected-warning {{subscript should be declared private because its index uses a private type}} - func privateMethod(_: VeryPrivateType) -> Void {} // expected-warning {{method should be declared private because its parameter uses a private type}} {{none}} - enum PrivateRawValue: VeryPrivateType { // expected-warning {{enum should be declared private because its raw type uses a private type}} {{none}} + var privateVar: VeryPrivateType { fatalError() } // expected-error {{property must be declared private because its type uses a private type}} + var privateVar2 = VeryPrivateType() // expected-error {{property must be declared private because its type 'Container.VeryPrivateStruct.VeryPrivateType' (aka 'Int') uses a private type}} + typealias PrivateAlias = VeryPrivateType // expected-error {{type alias must be declared private because its underlying type uses a private type}} + subscript(_: VeryPrivateType) -> Void { return () } // expected-error {{subscript must be declared private because its index uses a private type}} + func privateMethod(_: VeryPrivateType) -> Void {} // expected-error {{method must be declared private because its parameter uses a private type}} {{none}} + enum PrivateRawValue: VeryPrivateType { // expected-error {{enum must be declared private because its raw type uses a private type}} {{none}} case A } enum PrivatePayload { - case A(VeryPrivateType) // expected-warning {{enum case in an internal enum uses a private type}} {{none}} + case A(VeryPrivateType) // expected-error {{enum case in an internal enum uses a private type}} {{none}} } private class PrivateInnerClass {} // expected-note * {{declared here}} - class PrivateSuper: PrivateInnerClass {} // expected-warning {{class should be declared private because its superclass is private}} {{none}} + class PrivateSuper: PrivateInnerClass {} // expected-error {{class must be declared private because its superclass is private}} {{none}} } - fileprivate var privateVar: VeryPrivateStruct { fatalError() } // expected-warning {{property should not be declared fileprivate because its type uses a private type}} {{none}} - fileprivate typealias PrivateAlias = VeryPrivateStruct // expected-warning {{type alias should not be declared fileprivate because its underlying type uses a private type}} {{none}} - fileprivate subscript(_: VeryPrivateStruct) -> Void { return () } // expected-warning {{subscript should not be declared fileprivate because its index uses a private type}} {{none}} - fileprivate func privateMethod(_: VeryPrivateStruct) -> Void {} // expected-warning {{method should not be declared fileprivate because its parameter uses a private type}} {{none}} - fileprivate enum PrivateRawValue: VeryPrivateStruct {} // expected-warning {{enum should not be declared fileprivate because its raw type uses a private type}} {{none}} + fileprivate var privateVar: VeryPrivateStruct { fatalError() } // expected-error {{property cannot be declared fileprivate because its type uses a private type}} {{none}} + fileprivate typealias PrivateAlias = VeryPrivateStruct // expected-error {{type alias cannot be declared fileprivate because its underlying type uses a private type}} {{none}} + fileprivate subscript(_: VeryPrivateStruct) -> Void { return () } // expected-error {{subscript cannot be declared fileprivate because its index uses a private type}} {{none}} + fileprivate func privateMethod(_: VeryPrivateStruct) -> Void {} // expected-error {{method cannot be declared fileprivate because its parameter uses a private type}} {{none}} + fileprivate enum PrivateRawValue: VeryPrivateStruct {} // expected-error {{enum cannot be declared fileprivate because its raw type uses a private type}} {{none}} // expected-error@-1 {{raw type 'Container.VeryPrivateStruct' is not expressible by any literal}} // expected-error@-2 {{'Container.PrivateRawValue' declares raw type 'Container.VeryPrivateStruct', but does not conform to RawRepresentable and conformance could not be synthesized}} // expected-error@-3 {{RawRepresentable conformance cannot be synthesized because raw type 'Container.VeryPrivateStruct' is not Equatable}} fileprivate enum PrivatePayload { - case A(VeryPrivateStruct) // expected-warning {{enum case in an internal enum uses a private type}} {{none}} + case A(VeryPrivateStruct) // expected-error {{enum case in an internal enum uses a private type}} {{none}} } private class PrivateInnerClass {} // expected-note * {{declared here}} - fileprivate class PrivateSuperClass: PrivateInnerClass {} // expected-warning {{class should not be declared fileprivate because its superclass is private}} {{none}} - fileprivate class PrivateGenericUser where T: PrivateInnerClass {} // expected-warning {{generic class should not be declared fileprivate because its generic requirement uses a private type}} {{none}} + fileprivate class PrivateSuperClass: PrivateInnerClass {} // expected-error {{class cannot be declared fileprivate because its superclass is private}} {{none}} + fileprivate class PrivateGenericUser where T: PrivateInnerClass {} // expected-error {{generic class cannot be declared fileprivate because its generic requirement uses a private type}} {{none}} } fileprivate struct SR2579 { private struct Inner { private struct InnerPrivateType {} - var innerProperty = InnerPrivateType() // expected-warning {{property should be declared private because its type 'SR2579.Inner.InnerPrivateType' uses a private type}} + var innerProperty = InnerPrivateType() // expected-error {{property must be declared private because its type 'SR2579.Inner.InnerPrivateType' uses a private type}} } // FIXME: We need better errors when one access violation results in more // downstream. - private var outerProperty = Inner().innerProperty // expected-warning {{property should not be declared in this context because its type 'SR2579.Inner.InnerPrivateType' uses a private type}} - var outerProperty2 = Inner().innerProperty // expected-warning {{property should be declared private because its type 'SR2579.Inner.InnerPrivateType' uses a private type}} + private var outerProperty = Inner().innerProperty // expected-error {{property cannot be declared in this context because its type 'SR2579.Inner.InnerPrivateType' uses a private type}} + var outerProperty2 = Inner().innerProperty // expected-error {{property must be declared private because its type 'SR2579.Inner.InnerPrivateType' uses a private type}} } diff --git a/test/Sema/substring_to_string_conversion_swift3.swift b/test/Sema/substring_to_string_conversion_swift3.swift index 1706b3940d3..8035c9286a4 100644 --- a/test/Sema/substring_to_string_conversion_swift3.swift +++ b/test/Sema/substring_to_string_conversion_swift3.swift @@ -45,7 +45,7 @@ do { // CTP_ClosureResult do { - [ss].map { (x: Substring) -> String in x } // expected-error {{declared closure result 'String' is incompatible with contextual type '_'}} + [ss].map { (x: Substring) -> String in x } // expected-error {{'Substring' is not convertible to 'String'}} } // CTP_ArrayElement diff --git a/test/Serialization/Recovery/typedefs.swift b/test/Serialization/Recovery/typedefs.swift index b7c960be65d..4912a6a2624 100644 --- a/test/Serialization/Recovery/typedefs.swift +++ b/test/Serialization/Recovery/typedefs.swift @@ -38,11 +38,11 @@ public func testVTableBuilding(user: User) { } // CHECK-IR: ret void #if VERIFY -let _: String = useAssoc(ImportedType.self) // expected-error {{cannot convert call result type '_.Assoc?' to expected type 'String'}} +let _: String = useAssoc(ImportedType.self) // expected-error {{cannot convert value of type 'Int32?' to specified type 'String'}} let _: Bool? = useAssoc(ImportedType.self) // expected-error {{cannot convert value of type 'Int32?' to specified type 'Bool?'}} let _: Int32? = useAssoc(ImportedType.self) -let _: String = useAssoc(AnotherType.self) // expected-error {{cannot convert call result type '_.Assoc?' to expected type 'String'}} +let _: String = useAssoc(AnotherType.self) // expected-error {{cannot convert value of type 'AnotherType.Assoc?' (aka 'Optional') to specified type 'String'}} let _: Bool? = useAssoc(AnotherType.self) // expected-error {{cannot convert value of type 'AnotherType.Assoc?' (aka 'Optional') to specified type 'Bool?'}} let _: Int32? = useAssoc(AnotherType.self) diff --git a/test/Serialization/sil-imported-enums.swift b/test/Serialization/sil-imported-enums.swift index 38e1f474db8..7b5890d3a9a 100644 --- a/test/Serialization/sil-imported-enums.swift +++ b/test/Serialization/sil-imported-enums.swift @@ -2,12 +2,12 @@ // RUN: mkdir -p %t // FIXME: BEGIN -enable-source-import hackaround -// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-module -o %t %clang-importer-sdk-path/swift-modules/CoreGraphics.swift -// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-module -o %t %clang-importer-sdk-path/swift-modules/Foundation.swift +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-module -sil-serialize-witness-tables -o %t %clang-importer-sdk-path/swift-modules/CoreGraphics.swift +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-module -sil-serialize-witness-tables -o %t %clang-importer-sdk-path/swift-modules/Foundation.swift // FIXME: END -enable-source-import hackaround -// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-module -o %t -parse-as-library %S/Inputs/use_imported_enums.swift -module-name UsesImportedEnums -// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-sil %s | %FileCheck %s +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-module -sil-serialize-witness-tables -o %t -parse-as-library %S/Inputs/use_imported_enums.swift -module-name UsesImportedEnums +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-sil -sil-serialize-witness-tables %s | %FileCheck %s // REQUIRES: objc_interop diff --git a/test/SourceKit/CodeComplete/Inputs/filter-rules/hideDesc.json b/test/SourceKit/CodeComplete/Inputs/filter-rules/hideDesc.json new file mode 100644 index 00000000000..d892d805f75 --- /dev/null +++ b/test/SourceKit/CodeComplete/Inputs/filter-rules/hideDesc.json @@ -0,0 +1,10 @@ +[ + { + key.kind: source.codecompletion.description, + key.hide: 1, + key.names: [ + "over(Int)", + "[Int]" + ] + } +] diff --git a/test/SourceKit/CodeComplete/Inputs/filter-rules/showDesc.json b/test/SourceKit/CodeComplete/Inputs/filter-rules/showDesc.json new file mode 100644 index 00000000000..f04b9263c16 --- /dev/null +++ b/test/SourceKit/CodeComplete/Inputs/filter-rules/showDesc.json @@ -0,0 +1,16 @@ +[ + { + key.kind: source.codecompletion.identifier, + key.hide: 1, + key.names: [ + "[]" + ] + }, + { + key.kind: source.codecompletion.description, + key.hide: 0, + key.names: [ + "[Float]" + ] + } +] diff --git a/test/SourceKit/CodeComplete/complete_filter_rules.swift b/test/SourceKit/CodeComplete/complete_filter_rules.swift index 9e65fdb7c7c..8be325740eb 100644 --- a/test/SourceKit/CodeComplete/complete_filter_rules.swift +++ b/test/SourceKit/CodeComplete/complete_filter_rules.swift @@ -183,3 +183,50 @@ func testHideOp10() { struct local {} local#^HIDE_OP_10^# } + +// RUN: %complete-test -filter-rules=%S/Inputs/filter-rules/hideDesc.json -tok=HIDE_DESC_1 %s -- -F %S/../Inputs/libIDE-mock-sdk | %FileCheck %s -check-prefix=HIDE_DESC_1 +func testHideDesc1() { + struct Local { + func over(_: Int) {} + func over(_: Float) {} + } + + Local().#^HIDE_DESC_1^# +} +// HIDE_DESC_1-NOT: over +// HIDE_DESC_1: over(Float) +// HIDE_DESC_1-NOT: over + +// RUN: %complete-test -filter-rules=%S/Inputs/filter-rules/hideDesc.json -tok=HIDE_DESC_2 %s -- -F %S/../Inputs/libIDE-mock-sdk | %FileCheck %s -check-prefix=HIDE_DESC_2 +// RUN: %complete-test -filter-rules=%S/Inputs/filter-rules/hideDesc.json -tok=HIDE_DESC_3 %s -- -F %S/../Inputs/libIDE-mock-sdk | %FileCheck %s -check-prefix=HIDE_DESC_2 +func testHideDesc2() { + struct Local { + subscript(_: Int) -> Int { return 0 } + subscript(_: Float) -> Float { return 0.0 } + } + + Local()#^HIDE_DESC_2^# + + let local = Local() + #^HIDE_DESC_3,local^# +} +// HIDE_DESC_2-NOT: [Int] +// HIDE_DESC_2: [Float] +// HIDE_DESC_2-NOT: [Int] + +// RUN: %complete-test -filter-rules=%S/Inputs/filter-rules/showDesc.json -tok=SHOW_DESC_2 %s -- -F %S/../Inputs/libIDE-mock-sdk | %FileCheck %s -check-prefix=SHOW_DESC_2 +// RUN: %complete-test -filter-rules=%S/Inputs/filter-rules/showDesc.json -tok=SHOW_DESC_3 %s -- -F %S/../Inputs/libIDE-mock-sdk | %FileCheck %s -check-prefix=SHOW_DESC_2 +func testHideDesc2() { + struct Local { + subscript(_: Int) -> Int { return 0 } + subscript(_: Float) -> Float { return 0.0 } + } + + Local()#^SHOW_DESC_2^# + + let local = Local() + #^SHOW_DESC_3,local^# +} +// SHOW_DESC_2-NOT: [Int] +// SHOW_DESC_2: [Float] +// SHOW_DESC_2-NOT: [Int] diff --git a/test/SourceKit/CursorInfo/rdar_18677108-2.swift.response b/test/SourceKit/CursorInfo/rdar_18677108-2.swift.response index 8ddb74916c3..7afe9c239a4 100644 --- a/test/SourceKit/CursorInfo/rdar_18677108-2.swift.response +++ b/test/SourceKit/CursorInfo/rdar_18677108-2.swift.response @@ -5,7 +5,7 @@ key.filepath: rdar_18677108-2-a.swift, key.severity: source.diagnostic.severity.error, key.description: "expected ')' in expression list", - key.diagnostic_stage: source.diagnostic.stage.swift.parse, + key.diagnostic_stage: source.diagnostic.stage.swift.sema, key.diagnostics: [ { key.line: 5, @@ -22,7 +22,7 @@ key.filepath: rdar_18677108-2-a.swift, key.severity: source.diagnostic.severity.error, key.description: "expected '}' at end of brace statement", - key.diagnostic_stage: source.diagnostic.stage.swift.parse, + key.diagnostic_stage: source.diagnostic.stage.swift.sema, key.diagnostics: [ { key.line: 4, @@ -39,7 +39,7 @@ key.filepath: rdar_18677108-2-a.swift, key.severity: source.diagnostic.severity.error, key.description: "expected '}' in class", - key.diagnostic_stage: source.diagnostic.stage.swift.parse, + key.diagnostic_stage: source.diagnostic.stage.swift.sema, key.diagnostics: [ { key.line: 2, diff --git a/test/SourceKit/DocSupport/doc_swift_module.swift.response b/test/SourceKit/DocSupport/doc_swift_module.swift.response index 5dcb3b60b7d..fe897b1db6b 100644 --- a/test/SourceKit/DocSupport/doc_swift_module.swift.response +++ b/test/SourceKit/DocSupport/doc_swift_module.swift.response @@ -124,7 +124,7 @@ struct S2 : P3 { typealias T = cake.S2 } -func genfoo(x ix: T1, y iy: T2) where T1 : Prot, T2 : cake.C1, T1.Element == Int +func genfoo(x ix: T1, y iy: T2) where T1 : Prot, T2 : cake.C1, T1.Element == cake.C1.Element [ @@ -1109,6 +1109,18 @@ func genfoo(x ix: T1, y iy: T2) where T1 : Prot, T2 : cake.C1, T1.Elemen key.offset: 1337, key.length: 7 }, + { + key.kind: source.lang.swift.syntaxtype.typeidentifier, + key.offset: 1348, + key.length: 4 + }, + { + key.kind: source.lang.swift.ref.class, + key.name: "C1", + key.usr: "s:4cake2C1C", + key.offset: 1353, + key.length: 2 + }, { key.kind: source.lang.swift.syntaxtype.argument, key.offset: 1283, @@ -1130,11 +1142,11 @@ func genfoo(x ix: T1, y iy: T2) where T1 : Prot, T2 : cake.C1, T1.Elemen key.length: 2 }, { - key.kind: source.lang.swift.ref.struct, - key.name: "Int", - key.usr: "s:Si", - key.offset: 1348, - key.length: 3 + key.kind: source.lang.swift.ref.typealias, + key.name: "Element", + key.usr: "s:4cake2C1C7Elementa", + key.offset: 1356, + key.length: 7 } ] [ @@ -1809,12 +1821,12 @@ func genfoo(x ix: T1, y iy: T2) where T1 : Prot, T2 : cake.C1, T1.Elemen key.description: "T2 : C1" }, { - key.description: "T1.Element == Int" + key.description: "T1.Element == C1.Element" } ], key.offset: 1263, - key.length: 88, - key.fully_annotated_decl: "func genfoo<T1, T2>(x ix: T1, y iy: T2) where T1 : Prot, T2 : C1, T1.Element == Int", + key.length: 100, + key.fully_annotated_decl: "func genfoo<T1, T2>(x ix: T1, y iy: T2) where T1 : Prot, T2 : C1, T1.Element == C1.Element", key.entities: [ { key.kind: source.lang.swift.decl.var.local, diff --git a/test/SourceKit/Sema/sema_diag_after_edit_fixit.swift b/test/SourceKit/Sema/sema_diag_after_edit_fixit.swift index 4d9f75a94c6..1ec6fb35a73 100644 --- a/test/SourceKit/Sema/sema_diag_after_edit_fixit.swift +++ b/test/SourceKit/Sema/sema_diag_after_edit_fixit.swift @@ -4,7 +4,7 @@ let a = 0; let b = 0 }; unresolved // Test that offsets of diagnostic ranges and fixits get updated correctly after the edit request // RUN: %sourcekitd-test -req=open %s -- %s == -req=print-diags %s \ -// RUN: == -req=edit -pos=2:1 -replace="_" -length=5 %s -print-raw-response \ +// RUN: == -req=edit -pos=2:1 -replace="_" -length=5 %s == -req=print-diags %s \ // RUN: | %FileCheck %s // CHECK: key.line: 2, diff --git a/test/SourceKit/Sema/sema_playground.swift.response b/test/SourceKit/Sema/sema_playground.swift.response index c805ee243eb..9659e116e45 100644 --- a/test/SourceKit/Sema/sema_playground.swift.response +++ b/test/SourceKit/Sema/sema_playground.swift.response @@ -12,6 +12,6 @@ key.filepath: sema_playground.swift, key.severity: source.diagnostic.severity.error, key.description: "expected numeric value following '$'", - key.diagnostic_stage: source.diagnostic.stage.swift.parse + key.diagnostic_stage: source.diagnostic.stage.swift.sema } ] diff --git a/test/SourceKit/SyntaxMapData/diags.swift.response b/test/SourceKit/SyntaxMapData/diags.swift.response index 0f5fb43780b..9a702284a2b 100644 --- a/test/SourceKit/SyntaxMapData/diags.swift.response +++ b/test/SourceKit/SyntaxMapData/diags.swift.response @@ -6,7 +6,7 @@ key.filepath: parse_error.swift, key.severity: source.diagnostic.severity.error, key.description: "expected '(' in argument list of function declaration", - key.diagnostic_stage: source.diagnostic.stage.swift.parse, + key.diagnostic_stage: source.diagnostic.stage.swift.sema, key.fixits: [ { key.offset: 26, @@ -37,7 +37,7 @@ key.filepath: parse_error.swift, key.severity: source.diagnostic.severity.error, key.description: "expected '(' in argument list of function declaration", - key.diagnostic_stage: source.diagnostic.stage.swift.parse, + key.diagnostic_stage: source.diagnostic.stage.swift.sema, key.fixits: [ { key.offset: 29, diff --git a/test/Syntax/Inputs/serialize_multiple_decls.json b/test/Syntax/Inputs/serialize_multiple_decls.json new file mode 100644 index 00000000000..286afe4ac12 --- /dev/null +++ b/test/Syntax/Inputs/serialize_multiple_decls.json @@ -0,0 +1,148 @@ +[ + { + "kind": "UnknownDecl", + "layout": [ + { + "tokenKind": { + "kind": "kw_struct" + }, + "leadingTrivia": [ + { + "kind": "LineComment", + "value": "\/\/ RUN: %swift-syntax-test -input-source-filename %s -serialize-raw-tree > %t" + }, + { + "kind": "Newline", + "value": 1 + }, + { + "kind": "LineComment", + "value": "\/\/ RUN: diff %t %S\/Inputs\/serialize_multiple_decls.json" + }, + { + "kind": "Newline", + "value": 2 + } + ], + "trailingTrivia": [ + { + "kind": "Space", + "value": 1 + } + ], + "presence": "Present" + }, + { + "tokenKind": { + "kind": "identifier", + "text": "A" + }, + "leadingTrivia": [ + + ], + "trailingTrivia": [ + { + "kind": "Space", + "value": 1 + } + ], + "presence": "Present" + }, + { + "tokenKind": { + "kind": "l_brace" + }, + "leadingTrivia": [ + + ], + "trailingTrivia": [ + + ], + "presence": "Present" + }, + { + "tokenKind": { + "kind": "r_brace" + }, + "leadingTrivia": [ + { + "kind": "Newline", + "value": 1 + } + ], + "trailingTrivia": [ + + ], + "presence": "Present" + } + ], + "presence": "Present" + }, + { + "kind": "UnknownDecl", + "layout": [ + { + "tokenKind": { + "kind": "kw_struct" + }, + "leadingTrivia": [ + { + "kind": "Newline", + "value": 2 + } + ], + "trailingTrivia": [ + { + "kind": "Space", + "value": 1 + } + ], + "presence": "Present" + }, + { + "tokenKind": { + "kind": "identifier", + "text": "B" + }, + "leadingTrivia": [ + + ], + "trailingTrivia": [ + { + "kind": "Space", + "value": 1 + } + ], + "presence": "Present" + }, + { + "tokenKind": { + "kind": "l_brace" + }, + "leadingTrivia": [ + + ], + "trailingTrivia": [ + + ], + "presence": "Present" + }, + { + "tokenKind": { + "kind": "r_brace" + }, + "leadingTrivia": [ + { + "kind": "Newline", + "value": 1 + } + ], + "trailingTrivia": [ + + ], + "presence": "Present" + } + ], + "presence": "Present" + } +] diff --git a/test/Syntax/Inputs/serialize_struct_decl.json b/test/Syntax/Inputs/serialize_struct_decl.json new file mode 100644 index 00000000000..a59a327a0e7 --- /dev/null +++ b/test/Syntax/Inputs/serialize_struct_decl.json @@ -0,0 +1,265 @@ +[ + { + "kind": "UnknownDecl", + "layout": [ + { + "tokenKind": { + "kind": "kw_struct" + }, + "leadingTrivia": [ + { + "kind": "LineComment", + "value": "\/\/ RUN: %swift-syntax-test -input-source-filename %s -serialize-raw-tree > %t" + }, + { + "kind": "Newline", + "value": 1 + }, + { + "kind": "LineComment", + "value": "\/\/ RUN: diff %t %S\/Inputs\/serialize_struct_decl.json" + }, + { + "kind": "Newline", + "value": 2 + } + ], + "trailingTrivia": [ + { + "kind": "Space", + "value": 1 + } + ], + "presence": "Present" + }, + { + "tokenKind": { + "kind": "identifier", + "text": "Foo" + }, + "leadingTrivia": [ + + ], + "trailingTrivia": [ + { + "kind": "Space", + "value": 1 + } + ], + "presence": "Present" + }, + { + "tokenKind": { + "kind": "l_brace" + }, + "leadingTrivia": [ + + ], + "trailingTrivia": [ + + ], + "presence": "Present" + }, + { + "tokenKind": { + "kind": "kw_let" + }, + "leadingTrivia": [ + { + "kind": "Newline", + "value": 1 + }, + { + "kind": "Space", + "value": 2 + } + ], + "trailingTrivia": [ + { + "kind": "Space", + "value": 3 + } + ], + "presence": "Present" + }, + { + "tokenKind": { + "kind": "identifier", + "text": "bar" + }, + "leadingTrivia": [ + + ], + "trailingTrivia": [ + { + "kind": "Space", + "value": 1 + } + ], + "presence": "Present" + }, + { + "tokenKind": { + "kind": "colon" + }, + "leadingTrivia": [ + + ], + "trailingTrivia": [ + { + "kind": "Space", + "value": 1 + } + ], + "presence": "Present" + }, + { + "tokenKind": { + "kind": "identifier", + "text": "Int" + }, + "leadingTrivia": [ + + ], + "trailingTrivia": [ + + ], + "presence": "Present" + }, + { + "tokenKind": { + "kind": "kw_let" + }, + "leadingTrivia": [ + { + "kind": "Newline", + "value": 2 + }, + { + "kind": "Space", + "value": 2 + } + ], + "trailingTrivia": [ + { + "kind": "Space", + "value": 1 + } + ], + "presence": "Present" + }, + { + "tokenKind": { + "kind": "identifier", + "text": "baz" + }, + "leadingTrivia": [ + + ], + "trailingTrivia": [ + { + "kind": "Space", + "value": 1 + } + ], + "presence": "Present" + }, + { + "tokenKind": { + "kind": "colon" + }, + "leadingTrivia": [ + + ], + "trailingTrivia": [ + { + "kind": "Space", + "value": 1 + } + ], + "presence": "Present" + }, + { + "tokenKind": { + "kind": "identifier", + "text": "Array" + }, + "leadingTrivia": [ + + ], + "trailingTrivia": [ + { + "kind": "Space", + "value": 1 + } + ], + "presence": "Present" + }, + { + "tokenKind": { + "kind": "oper_binary_spaced", + "text": "<" + }, + "leadingTrivia": [ + + ], + "trailingTrivia": [ + { + "kind": "Space", + "value": 1 + } + ], + "presence": "Present" + }, + { + "tokenKind": { + "kind": "identifier", + "text": "Int" + }, + "leadingTrivia": [ + + ], + "trailingTrivia": [ + { + "kind": "Space", + "value": 1 + } + ], + "presence": "Present" + }, + { + "tokenKind": { + "kind": "oper_binary_spaced", + "text": ">" + }, + "leadingTrivia": [ + + ], + "trailingTrivia": [ + + ], + "presence": "Present" + }, + { + "tokenKind": { + "kind": "r_brace" + }, + "leadingTrivia": [ + { + "kind": "Newline", + "value": 1 + }, + { + "kind": "Space", + "value": 6 + } + ], + "trailingTrivia": [ + + ], + "presence": "Present" + } + ], + "presence": "Present" + } +] diff --git a/test/Syntax/serialize_multiple_decls.swift b/test/Syntax/serialize_multiple_decls.swift new file mode 100644 index 00000000000..e0982858452 --- /dev/null +++ b/test/Syntax/serialize_multiple_decls.swift @@ -0,0 +1,8 @@ +// RUN: %swift-syntax-test -input-source-filename %s -serialize-raw-tree > %t +// RUN: diff %t %S/Inputs/serialize_multiple_decls.json + +struct A { +} + +struct B { +} diff --git a/test/Syntax/serialize_struct_decl.swift b/test/Syntax/serialize_struct_decl.swift new file mode 100644 index 00000000000..9ee30e80b71 --- /dev/null +++ b/test/Syntax/serialize_struct_decl.swift @@ -0,0 +1,8 @@ +// RUN: %swift-syntax-test -input-source-filename %s -serialize-raw-tree > %t +// RUN: diff %t %S/Inputs/serialize_struct_decl.json + +struct Foo { + let bar : Int + + let baz : Array < Int > + } diff --git a/test/TBD/class.swift b/test/TBD/class.swift index 4c7b9aff6b8..d81f4bd68d4 100644 --- a/test/TBD/class.swift +++ b/test/TBD/class.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -emit-ir -o- -parse-as-library -module-name test -validate-tbd-against-ir=all %s +// RUN: %target-swift-frontend -emit-ir -o- -parse-as-library -module-name test -validate-tbd-against-ir=missing %s open class OpenNothing {} diff --git a/test/api-digester/Inputs/cake.swift b/test/api-digester/Inputs/cake.swift index 5a7906cc415..52595ffff8e 100644 --- a/test/api-digester/Inputs/cake.swift +++ b/test/api-digester/Inputs/cake.swift @@ -7,8 +7,10 @@ public struct S1 { public func foo6() -> Void {} } -public class C1 { +public class C0 {} + +public class C1: C0 { open class func foo1() {} public weak var Ins : C1? public unowned var Ins2 : C1 = C1() -} \ No newline at end of file +} diff --git a/test/api-digester/Inputs/cake1.swift b/test/api-digester/Inputs/cake1.swift index 3932eea40d4..c2f812529cd 100644 --- a/test/api-digester/Inputs/cake1.swift +++ b/test/api-digester/Inputs/cake1.swift @@ -13,6 +13,7 @@ public class C1 { public weak var CIIns1 : C1? public var CIIns2 : C1? public func foo3(a : Void?) {} + public func foo4(a : Void?) {} } public class C3 {} diff --git a/test/api-digester/Inputs/cake2.swift b/test/api-digester/Inputs/cake2.swift index e9407ec721d..fb4ada94d93 100644 --- a/test/api-digester/Inputs/cake2.swift +++ b/test/api-digester/Inputs/cake2.swift @@ -7,7 +7,11 @@ public struct S1 { public func foo5(x : Int, y: Int, z: Int) {} } -public class C1 { +public class C0 { + public func foo4(a : Void?) {} +} + +public class C1: C0 { public func foo1() {} public func foo2(_ : ()->()) {} public var CIIns1 : C1? diff --git a/test/api-digester/Outputs/Cake.txt b/test/api-digester/Outputs/Cake.txt index ba2b822c686..07f1e1d7d12 100644 --- a/test/api-digester/Outputs/Cake.txt +++ b/test/api-digester/Outputs/Cake.txt @@ -1,7 +1,6 @@ /* Removed Decls */ Class C3 has been removed -Constructor C1.init() has been removed Constructor Somestruct2.init(_:) has been removed /* Moved Decls */ diff --git a/test/api-digester/Outputs/cake.json b/test/api-digester/Outputs/cake.json index 41ab70dc0d6..07e05eee308 100644 --- a/test/api-digester/Outputs/cake.json +++ b/test/api-digester/Outputs/cake.json @@ -3,6 +3,33 @@ "name": "TopLevel", "printedName": "TopLevel", "children": [ + { + "kind": "TypeDecl", + "name": "C0", + "printedName": "C0", + "declKind": "Class", + "usr": "s:4cake2C0C", + "location": "", + "moduleName": "cake", + "children": [ + { + "kind": "Constructor", + "name": "init", + "printedName": "init()", + "declKind": "Constructor", + "usr": "s:4cake2C0CACycfc", + "location": "", + "moduleName": "cake", + "children": [ + { + "kind": "TypeNominal", + "name": "C0", + "printedName": "C0" + } + ] + } + ] + }, { "kind": "TypeDecl", "name": "S1", @@ -95,6 +122,7 @@ "usr": "s:4cake2C1C", "location": "", "moduleName": "cake", + "superclassUsr": "s:4cake2C0C", "children": [ { "kind": "Function", diff --git a/test/attr/attr_autoclosure.swift b/test/attr/attr_autoclosure.swift index 8add38df263..f9edf793dda 100644 --- a/test/attr/attr_autoclosure.swift +++ b/test/attr/attr_autoclosure.swift @@ -55,7 +55,7 @@ func overloadedEach(_ source: P, _ closure: @escaping () -> ()) { struct S : P2 { typealias Element = Int func each(_ closure: @autoclosure () -> ()) { - // expected-note@-1{{parameter 'closure' is implicitly non-escaping because it was declared @autoclosure}} + // expected-note@-1{{parameter 'closure' is implicitly non-escaping}} overloadedEach(self, closure) // expected-error {{passing non-escaping parameter 'closure' to function expecting an @escaping closure}} } @@ -93,7 +93,7 @@ class Sub : Super { func func12_sink(_ x: @escaping () -> Int) { } func func12a(_ x: @autoclosure () -> Int) { - // expected-note@-1{{parameter 'x' is implicitly non-escaping because it was declared @autoclosure}} + // expected-note@-1{{parameter 'x' is implicitly non-escaping}} func12_sink(x) // expected-error {{passing non-escaping parameter 'x' to function expecting an @escaping closure}} } diff --git a/test/attr/attr_dynamic_infer.swift b/test/attr/attr_dynamic_infer.swift index 4fc57ba3cf3..32b3ced042a 100644 --- a/test/attr/attr_dynamic_infer.swift +++ b/test/attr/attr_dynamic_infer.swift @@ -59,7 +59,7 @@ extension Sub { @objc class FinalTests {} extension FinalTests { - // CHECK: @objc final func foo + // CHECK: @objc final func foo final func foo() { } // CHECK: @objc final var prop: Super @@ -77,5 +77,11 @@ extension FinalTests { // CHECK: @objc final set set { } } + + // CHECK: @objc static var x + static var x: Int = 0 + + // CHECK: @objc static func bar + static func bar() { } } diff --git a/test/attr/attr_inlineable.swift b/test/attr/attr_inlineable.swift index ebca886ddc2..fbfa2aa69e1 100644 --- a/test/attr/attr_inlineable.swift +++ b/test/attr/attr_inlineable.swift @@ -5,17 +5,14 @@ // expected-error@-1 {{@_inlineable cannot be applied to this declaration}} private func privateFunction() {} -// expected-note@-1 5{{global function 'privateFunction()' is not '@_versioned' or public}} +// expected-note@-1{{global function 'privateFunction()' is not '@_versioned' or public}} fileprivate func fileprivateFunction() {} -// expected-note@-1 5{{global function 'fileprivateFunction()' is not '@_versioned' or public}} +// expected-note@-1{{global function 'fileprivateFunction()' is not '@_versioned' or public}} func internalFunction() {} -// expected-note@-1 5{{global function 'internalFunction()' is not '@_versioned' or public}} +// expected-note@-1{{global function 'internalFunction()' is not '@_versioned' or public}} @_versioned func versionedFunction() {} public func publicFunction() {} -func internalIntFunction() -> Int {} -// expected-note@-1 2{{global function 'internalIntFunction()' is not '@_versioned' or public}} - private struct PrivateStruct {} // expected-note@-1 3{{struct 'PrivateStruct' is not '@_versioned' or public}} struct InternalStruct {} @@ -136,72 +133,6 @@ public struct Struct { } } -func internalFunctionWithDefaultValue( - x: Int = { - struct Nested {} - // OK - - publicFunction() - // OK - versionedFunction() - // OK - internalFunction() - // OK - fileprivateFunction() - // OK - privateFunction() - // OK - - return 0 - }(), - y: Int = internalIntFunction()) {} - -@_versioned func versionedFunctionWithDefaultValue( - x: Int = { - struct Nested {} - // expected-error@-1 {{type 'Nested' cannot be nested inside a default argument value}} - - // FIXME: Some errors below are diagnosed twice - - publicFunction() - // OK - versionedFunction() - // OK - internalFunction() - // expected-error@-1 2{{global function 'internalFunction()' is internal and cannot be referenced from a default argument value}} - fileprivateFunction() - // expected-error@-1 2{{global function 'fileprivateFunction()' is fileprivate and cannot be referenced from a default argument value}} - privateFunction() - // expected-error@-1 2{{global function 'privateFunction()' is private and cannot be referenced from a default argument value}} - - return 0 - }(), - y: Int = internalIntFunction()) {} - // expected-error@-1 {{global function 'internalIntFunction()' is internal and cannot be referenced from a default argument value}} - -public func publicFunctionWithDefaultValue( - x: Int = { - struct Nested {} - // expected-error@-1 {{type 'Nested' cannot be nested inside a default argument value}} - - // FIXME: Some errors below are diagnosed twice - - publicFunction() - // OK - versionedFunction() - // OK - internalFunction() - // expected-error@-1 2{{global function 'internalFunction()' is internal and cannot be referenced from a default argument value}} - fileprivateFunction() - // expected-error@-1 2{{global function 'fileprivateFunction()' is fileprivate and cannot be referenced from a default argument value}} - privateFunction() - // expected-error@-1 2{{global function 'privateFunction()' is private and cannot be referenced from a default argument value}} - - return 0 - }(), - y: Int = internalIntFunction()) {} - // expected-error@-1 {{global function 'internalIntFunction()' is internal and cannot be referenced from a default argument value}} - // Make sure protocol extension members can reference protocol requirements // (which do not inherit the @_versioned attribute). @_versioned diff --git a/test/attr/attr_noescape.swift b/test/attr/attr_noescape.swift index e3c0936e74b..05661be7ae6 100644 --- a/test/attr/attr_noescape.swift +++ b/test/attr/attr_noescape.swift @@ -170,7 +170,7 @@ func takeNoEscapeTest2(_ fn : @noescape () -> ()) { // expected-warning{{@noesc // Autoclosure implies noescape, but produce nice diagnostics so people know // why noescape problems happen. -func testAutoclosure(_ a : @autoclosure () -> Int) { // expected-note{{parameter 'a' is implicitly non-escaping because it was declared @autoclosure}} +func testAutoclosure(_ a : @autoclosure () -> Int) { // expected-note{{parameter 'a' is implicitly non-escaping}} doesEscape { a() } // expected-error {{closure use of non-escaping parameter 'a' may allow it to escape}} } @@ -304,6 +304,7 @@ func apply(_ f: @noescape (T) -> U, g: @noescape (@noescape (T) -> U) -> U // expected-warning@-2{{@noescape is the default and is deprecated}} {{46-56=}} // expected-warning@-3{{@noescape is the default and is deprecated}} {{57-66=}} return g(f) + // expected-warning@-1{{passing a non-escaping function parameter 'f' to a call to a non-escaping function parameter}} } // @noescape cannot be applied to locals, leading to duplication of code diff --git a/test/attr/attr_specialize.swift b/test/attr/attr_specialize.swift index 5fc979d15e9..a3cea524d0a 100644 --- a/test/attr/attr_specialize.swift +++ b/test/attr/attr_specialize.swift @@ -87,7 +87,7 @@ struct FloatElement : HasElt { typealias Element = Float } @_specialize(where T == FloatElement) -@_specialize(where T == IntElement) // expected-error{{associated type 'T.Element' cannot be equal to both 'Float' and 'Int'}} +@_specialize(where T == IntElement) // expected-error{{'T.Element' cannot be equal to both 'IntElement.Element' (aka 'Int') and 'Float'}} func sameTypeRequirement(_ t: T) where T.Element == Float {} @_specialize(where T == Sub) diff --git a/test/decl/ext/generic.swift b/test/decl/ext/generic.swift index a3b1b54e674..b9d61786637 100644 --- a/test/decl/ext/generic.swift +++ b/test/decl/ext/generic.swift @@ -158,3 +158,9 @@ struct S5 { } extension S5 : P4 {} + +// rdar://problem/21607421 +public typealias Array2 = Array +extension Array2 where QQQ : VVV {} +// expected-error@-1 {{use of undeclared type 'QQQ'}} +// expected-error@-2 {{use of undeclared type 'VVV'}} diff --git a/test/decl/ext/protocol.swift b/test/decl/ext/protocol.swift index 32b8c698c87..760d7dfd7d5 100644 --- a/test/decl/ext/protocol.swift +++ b/test/decl/ext/protocol.swift @@ -921,9 +921,10 @@ extension BadProto1 { } } +// rdar://problem/20756244 protocol BadProto3 { } typealias BadProto4 = BadProto3 -extension BadProto4 { } // expected-error{{protocol 'BadProto3' in the module being compiled cannot be extended via a type alias}}{{11-20=BadProto3}} +extension BadProto4 { } // okay typealias RawRepresentableAlias = RawRepresentable extension RawRepresentableAlias { } // okay @@ -948,6 +949,6 @@ class BadClass5 : BadProto5 {} // expected-error{{type 'BadClass5' does not conf typealias A = BadProto1 typealias B = BadProto1 -extension A & B { // expected-error{{protocol 'BadProto1' in the module being compiled cannot be extended via a type alias}} +extension A & B { // okay } diff --git a/test/decl/func/default-values-swift4.swift b/test/decl/func/default-values-swift4.swift new file mode 100644 index 00000000000..9c8732c3e9e --- /dev/null +++ b/test/decl/func/default-values-swift4.swift @@ -0,0 +1,80 @@ +// RUN: %target-typecheck-verify-swift -swift-version 4 +// RUN: %target-typecheck-verify-swift -swift-version 4 -enable-testing + +private func privateFunction() {} +// expected-note@-1 4{{global function 'privateFunction()' is not public}} +fileprivate func fileprivateFunction() {} +// expected-note@-1 4{{global function 'fileprivateFunction()' is not public}} +func internalFunction() {} +// expected-note@-1 4{{global function 'internalFunction()' is not public}} +@_versioned func versionedFunction() {} +public func publicFunction() {} + +func internalIntFunction() -> Int {} +// expected-note@-1 2{{global function 'internalIntFunction()' is not public}} + +func internalFunctionWithDefaultValue( + x: Int = { + struct Nested {} + // OK + + publicFunction() + // OK + versionedFunction() + // OK + internalFunction() + // OK + fileprivateFunction() + // OK + privateFunction() + // OK + + return 0 + }(), + y: Int = internalIntFunction()) {} + +@_versioned func versionedFunctionWithDefaultValue( + x: Int = { + struct Nested {} + // expected-error@-1 {{type 'Nested' cannot be nested inside a default argument value}} + + // FIXME: Some errors below are diagnosed twice + + publicFunction() + // OK + versionedFunction() + // OK + internalFunction() + // expected-error@-1 2{{global function 'internalFunction()' is internal and cannot be referenced from a default argument value}} + fileprivateFunction() + // expected-error@-1 2{{global function 'fileprivateFunction()' is fileprivate and cannot be referenced from a default argument value}} + privateFunction() + // expected-error@-1 2{{global function 'privateFunction()' is private and cannot be referenced from a default argument value}} + + return 0 + }(), + y: Int = internalIntFunction()) {} + // expected-error@-1 {{global function 'internalIntFunction()' is internal and cannot be referenced from a default argument value}} + +public func publicFunctionWithDefaultValue( + x: Int = { + struct Nested {} + // expected-error@-1 {{type 'Nested' cannot be nested inside a default argument value}} + + // FIXME: Some errors below are diagnosed twice + + publicFunction() + // OK + versionedFunction() + // OK + internalFunction() + // expected-error@-1 2{{global function 'internalFunction()' is internal and cannot be referenced from a default argument value}} + fileprivateFunction() + // expected-error@-1 2{{global function 'fileprivateFunction()' is fileprivate and cannot be referenced from a default argument value}} + privateFunction() + // expected-error@-1 2{{global function 'privateFunction()' is private and cannot be referenced from a default argument value}} + + return 0 + }(), + y: Int = internalIntFunction()) {} + // expected-error@-1 {{global function 'internalIntFunction()' is internal and cannot be referenced from a default argument value}} diff --git a/test/decl/protocol/conforms/associated_type.swift b/test/decl/protocol/conforms/associated_type.swift index be7e38c9627..92a5a79fe59 100644 --- a/test/decl/protocol/conforms/associated_type.swift +++ b/test/decl/protocol/conforms/associated_type.swift @@ -1,4 +1,5 @@ -// RUN: %target-typecheck-verify-swift +// RUN: %target-typecheck-verify-swift -swift-version 3 +// RUN: %target-typecheck-verify-swift -swift-version 4 class C { } @@ -9,3 +10,23 @@ protocol P { struct X : P { // expected-error{{type 'X' does not conform to protocol 'P'}} typealias AssocP = Int // expected-note{{possibly intended match 'X.AssocP' (aka 'Int') does not inherit from 'C'}} } + +// SR-5166 +protocol FooType { + associatedtype BarType + + func foo(bar: BarType) + func foo(action: (BarType) -> Void) +} + +protocol Bar {} + +class Foo: FooType { + typealias BarType = Bar + + func foo(bar: Bar) { + } + + func foo(action: (Bar) -> Void) { + } +} diff --git a/test/decl/protocol/conforms/fixit_stub_editor.swift b/test/decl/protocol/conforms/fixit_stub_editor.swift index eaf07c83f07..653c02b3e94 100644 --- a/test/decl/protocol/conforms/fixit_stub_editor.swift +++ b/test/decl/protocol/conforms/fixit_stub_editor.swift @@ -1,7 +1,7 @@ // RUN: %target-typecheck-verify-swift -diagnostics-editor-mode protocol P1 { - @available(iOS, unavailable) + @available(*, deprecated) func foo1() func foo2() } diff --git a/test/decl/protocol/req/where_clause.swift b/test/decl/protocol/req/where_clause.swift new file mode 100644 index 00000000000..27f3907d036 --- /dev/null +++ b/test/decl/protocol/req/where_clause.swift @@ -0,0 +1,18 @@ +// RUN: %target-typecheck-verify-swift + +// rdar://problem/31401161 +class C1 {} + +protocol P1 { + associatedtype Element +} + +protocol P2 : P1 { + associatedtype SubSequence : P1 // expected-note{{'SubSequence' declared here}} +} + +protocol P3 : P2 { + associatedtype SubSequence : P2 // expected-warning{{redeclaration of associated type 'SubSequence' from protocol 'P2' is better expressed as a 'where' clause on the protocol}} +} + +func foo(_: S) where S.SubSequence.Element == C1, S : P3 {} diff --git a/test/decl/protocol/special/coding/class_codable_failure_diagnostics.swift b/test/decl/protocol/special/coding/class_codable_failure_diagnostics.swift new file mode 100644 index 00000000000..3268dbb3e67 --- /dev/null +++ b/test/decl/protocol/special/coding/class_codable_failure_diagnostics.swift @@ -0,0 +1,133 @@ +// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -parse-as-library -swift-version 4 %s 2>&1 | %FileCheck %s + +// Codable class with non-Codable property. +class C1 : Codable { + class Nested {} + var a: String = "" + var b: Int = 0 + var c: Nested = Nested() + + // CHECK: error: type 'C1' does not conform to protocol 'Decodable' + // CHECK: note: cannot automatically synthesize 'Decodable' because 'C1.Nested' does not conform to 'Decodable' + // CHECK: note: protocol requires initializer 'init(from:)' with type 'Decodable' + + // CHECK: error: type 'C1' does not conform to protocol 'Encodable' + // CHECK: note: cannot automatically synthesize 'Encodable' because 'C1.Nested' does not conform to 'Encodable' + // CHECK: note: protocol requires function 'encode(to:)' with type 'Encodable' +} + +// Codable class with non-enum CodingKeys. +class C2 : Codable { + var a: String = "" + var b: Int = 0 + var c: Double? + + struct CodingKeys : CodingKey { + var stringValue = "" + var intValue = nil + init?(stringValue: String) {} + init?(intValue: Int) {} + } + + // CHECK: error: type 'C2' does not conform to protocol 'Decodable' + // CHECK: note: cannot automatically synthesize 'Decodable' because 'CodingKeys' is not an enum + // CHECK: note: protocol requires initializer 'init(from:)' with type 'Decodable' + + // CHECK: error: type 'C2' does not conform to protocol 'Encodable' + // CHECK: note: cannot automatically synthesize 'Encodable' because 'CodingKeys' is not an enum + // CHECK: note: protocol requires function 'encode(to:)' with type 'Encodable' +} + +// Codable class with CodingKeys not conforming to CodingKey. +class C3 : Codable { + var a: String = "" + var b: Int = 0 + var c: Double? + + enum CodingKeys : String { + case a + case b + case c + } + + // CHECK: error: type 'C3' does not conform to protocol 'Decodable' + // CHECK: note: cannot automatically synthesize 'Decodable' because 'CodingKeys' does not conform to CodingKey + // CHECK: note: protocol requires initializer 'init(from:)' with type 'Decodable' + + // CHECK: error: type 'C3' does not conform to protocol 'Encodable' + // CHECK: note: cannot automatically synthesize 'Encodable' because 'CodingKeys' does not conform to CodingKey + // CHECK: note: protocol requires function 'encode(to:)' with type 'Encodable' +} + +// Codable class with extraneous CodingKeys +class C4 : Codable { + var a: String = "" + var b: Int = 0 + var c: Double? + + enum CodingKeys : String, CodingKey { + case a + case a2 + case b + case b2 + case c + case c2 + } + + // CHECK: error: type 'C4' does not conform to protocol 'Decodable' + // CHECK: note: CodingKey case 'a2' does not match any stored properties + // CHECK: note: CodingKey case 'b2' does not match any stored properties + // CHECK: note: CodingKey case 'c2' does not match any stored properties + // CHECK: note: protocol requires initializer 'init(from:)' with type 'Decodable' + + // CHECK: error: type 'C4' does not conform to protocol 'Encodable' + // CHECK: note: CodingKey case 'a2' does not match any stored properties + // CHECK: note: CodingKey case 'b2' does not match any stored properties + // CHECK: note: CodingKey case 'c2' does not match any stored properties + // CHECK: note: protocol requires function 'encode(to:)' with type 'Encodable' +} + +// Codable class with non-decoded property (which has no default value). +class C5 : Codable { + var a: String = "" + var b: Int + var c: Double? + + enum CodingKeys : String, CodingKey { + case a + case c + } + + // CHECK: error: class 'C5' has no initializers + // CHECK: note: stored property 'b' without initial value prevents synthesized initializers + + // CHECK: error: type 'C5' does not conform to protocol 'Decodable' + // CHECK: note: cannot automatically synthesize 'Decodable' because 'b' does not have a matching CodingKey and does not have a default value + // CHECK: note: protocol requires initializer 'init(from:)' with type 'Decodable' +} + +// Codable class with non-decoded property (which has no default value). +class C6 : Codable { + var a: String = "" + var b: Int + var c: Double? + + enum CodingKeys : String, CodingKey { + case a + case c + } + + init() { + b = 5 + } + + // CHECK: error: type 'C6' does not conform to protocol 'Decodable' + // CHECK: note: cannot automatically synthesize 'Decodable' because 'b' does not have a matching CodingKey and does not have a default value + // CHECK: note: protocol requires initializer 'init(from:)' with type 'Decodable' +} + +// Classes cannot yet synthesize Encodable or Decodable in extensions. +class C7 {} +extension C7 : Codable {} +// CHECK: error: implementation of 'Decodable' cannot be automatically synthesized in an extension yet +// CHECK: error: implementation of 'Encodable' cannot be automatically synthesized in an extension yet diff --git a/test/decl/protocol/special/coding/class_codable_non_strong_vars.swift b/test/decl/protocol/special/coding/class_codable_non_strong_vars.swift new file mode 100644 index 00000000000..d6e6d24140e --- /dev/null +++ b/test/decl/protocol/special/coding/class_codable_non_strong_vars.swift @@ -0,0 +1,35 @@ +// RUN: %target-typecheck-verify-swift -verify-ignore-unknown + +// Classes with Codable properties (with non-strong ownership) should get +// derived conformance to Codable. +class NonStrongClass : Codable { + class NestedClass : Codable { + init() {} + } + + weak var x: NestedClass? = NestedClass() + unowned var y: NestedClass = NestedClass() + static var z: String = "foo" + + // These lines have to be within the NonStrongClass type because CodingKeys + // should be private. + func foo() { + // They should receive a synthesized CodingKeys enum. + let _ = NonStrongClass.CodingKeys.self + + // The enum should have a case for each of the vars. + let _ = NonStrongClass.CodingKeys.x + let _ = NonStrongClass.CodingKeys.y + + // Static vars should not be part of the CodingKeys enum. + let _ = NonStrongClass.CodingKeys.z // expected-error {{type 'NonStrongClass.CodingKeys' has no member 'z'}} + } +} + +// They should receive synthesized init(from:) and an encode(to:). +let _ = NonStrongClass.init(from:) +let _ = NonStrongClass.encode(to:) + +// The synthesized CodingKeys type should not be accessible from outside the +// class. +let _ = NonStrongClass.CodingKeys.self // expected-error {{'CodingKeys' is inaccessible due to 'private' protection level}} diff --git a/test/decl/protocol/special/coding/struct_codable_failure_diagnostics.swift b/test/decl/protocol/special/coding/struct_codable_failure_diagnostics.swift new file mode 100644 index 00000000000..c45691287d3 --- /dev/null +++ b/test/decl/protocol/special/coding/struct_codable_failure_diagnostics.swift @@ -0,0 +1,110 @@ +// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -parse-as-library -swift-version 4 %s 2>&1 | %FileCheck %s + +// Codable struct with non-Codable property. +struct S1 : Codable { + struct Nested {} + var a: String = "" + var b: Int = 0 + var c: Nested = Nested() + + // CHECK: error: type 'S1' does not conform to protocol 'Decodable' + // CHECK: note: cannot automatically synthesize 'Decodable' because 'S1.Nested' does not conform to 'Decodable' + // CHECK: note: protocol requires initializer 'init(from:)' with type 'Decodable' + + // CHECK: error: type 'S1' does not conform to protocol 'Encodable' + // CHECK: note: cannot automatically synthesize 'Encodable' because 'S1.Nested' does not conform to 'Encodable' + // CHECK: note: protocol requires function 'encode(to:)' with type 'Encodable' +} + +// Codable struct with non-enum CodingKeys. +struct S2 : Codable { + var a: String = "" + var b: Int = 0 + var c: Double? + + struct CodingKeys : CodingKey { + var stringValue: String = "" + var intValue: Int? = nil + init?(stringValue: String) {} + init?(intValue: Int) {} + } + + // CHECK: error: type 'S2' does not conform to protocol 'Decodable' + // CHECK: note: cannot automatically synthesize 'Decodable' because 'CodingKeys' is not an enum + // CHECK: note: protocol requires initializer 'init(from:)' with type 'Decodable' + + // CHECK: error: type 'S2' does not conform to protocol 'Encodable' + // CHECK: note: cannot automatically synthesize 'Encodable' because 'CodingKeys' is not an enum + // CHECK: note: protocol requires function 'encode(to:)' with type 'Encodable' +} + +// Codable struct with CodingKeys not conforming to CodingKey. +struct S3 : Codable { + var a: String = "" + var b: Int = 0 + var c: Double? + + enum CodingKeys : String { + case a + case b + case c + } + + // CHECK: error: type 'S3' does not conform to protocol 'Decodable' + // CHECK: note: cannot automatically synthesize 'Decodable' because 'CodingKeys' does not conform to CodingKey + // CHECK: note: protocol requires initializer 'init(from:)' with type 'Decodable' + + // CHECK: error: type 'S3' does not conform to protocol 'Encodable' + // CHECK: note: cannot automatically synthesize 'Encodable' because 'CodingKeys' does not conform to CodingKey + // CHECK: note: protocol requires function 'encode(to:)' with type 'Encodable' +} + +// Codable struct with extraneous CodingKeys +struct S4 : Codable { + var a: String = "" + var b: Int = 0 + var c: Double? + + enum CodingKeys : String, CodingKey { + case a + case a2 + case b + case b2 + case c + case c2 + } + + // CHECK: error: type 'S4' does not conform to protocol 'Decodable' + // CHECK: note: CodingKey case 'a2' does not match any stored properties + // CHECK: note: CodingKey case 'b2' does not match any stored properties + // CHECK: note: CodingKey case 'c2' does not match any stored properties + // CHECK: note: protocol requires initializer 'init(from:)' with type 'Decodable' + + // CHECK: error: type 'S4' does not conform to protocol 'Encodable' + // CHECK: note: CodingKey case 'a2' does not match any stored properties + // CHECK: note: CodingKey case 'b2' does not match any stored properties + // CHECK: note: CodingKey case 'c2' does not match any stored properties + // CHECK: note: protocol requires function 'encode(to:)' with type 'Encodable' +} + +// Codable struct with non-decoded property (which has no default value). +struct S5 : Codable { + var a: String = "" + var b: Int + var c: Double? + + enum CodingKeys : String, CodingKey { + case a + case c + } + + // CHECK: error: type 'S5' does not conform to protocol 'Decodable' + // CHECK: note: cannot automatically synthesize 'Decodable' because 'b' does not have a matching CodingKey and does not have a default value + // CHECK: note: protocol requires initializer 'init(from:)' with type 'Decodable' +} + +// Structs cannot yet synthesize Encodable or Decodable in extensions. +struct S6 {} +extension S6 : Codable {} +// CHECK: error: implementation of 'Decodable' cannot be automatically synthesized in an extension yet +// CHECK: error: implementation of 'Encodable' cannot be automatically synthesized in an extension yet diff --git a/test/decl/protocol/special/coding/struct_codable_non_strong_vars.swift b/test/decl/protocol/special/coding/struct_codable_non_strong_vars.swift new file mode 100644 index 00000000000..3efddff18b8 --- /dev/null +++ b/test/decl/protocol/special/coding/struct_codable_non_strong_vars.swift @@ -0,0 +1,35 @@ +// RUN: %target-typecheck-verify-swift -verify-ignore-unknown + +// Structs with Codable properties (with non-strong ownership) should get +// derived conformance to Codable. +struct NonStrongStruct : Codable { + class NestedClass : Codable { + init() {} + } + + weak var x: NestedClass? = NestedClass() + unowned var y: NestedClass = NestedClass() + static var z: String = "foo" + + // These lines have to be within the NonStrongStruct type because CodingKeys + // should be private. + func foo() { + // They should receive a synthesized CodingKeys enum. + let _ = NonStrongStruct.CodingKeys.self + + // The enum should have a case for each of the vars. + let _ = NonStrongStruct.CodingKeys.x + let _ = NonStrongStruct.CodingKeys.y + + // Static vars should not be part of the CodingKeys enum. + let _ = NonStrongStruct.CodingKeys.z // expected-error {{type 'NonStrongStruct.CodingKeys' has no member 'z'}} + } +} + +// They should receive synthesized init(from:) and an encode(to:). +let _ = NonStrongStruct.init(from:) +let _ = NonStrongStruct.encode(to:) + +// The synthesized CodingKeys type should not be accessible from outside the +// class. +let _ = NonStrongStruct.CodingKeys.self // expected-error {{'CodingKeys' is inaccessible due to 'private' protection level}} diff --git a/test/expr/closure/closures.swift b/test/expr/closure/closures.swift index cf13d3eb472..6d043e95651 100644 --- a/test/expr/closure/closures.swift +++ b/test/expr/closure/closures.swift @@ -14,7 +14,8 @@ var closure3a : () -> () -> (Int,Int) = {{ (4, 2) }} // multi-level closing. var closure3b : (Int,Int) -> (Int) -> (Int,Int) = {{ (4, 2) }} // expected-error{{contextual type for closure argument list expects 2 arguments, which cannot be implicitly ignored}} {{52-52=_,_ in }} var closure4 : (Int,Int) -> Int = { $0 + $1 } var closure5 : (Double) -> Int = { - $0 + 1.0 // expected-error {{cannot convert value of type 'Double' to closure result type 'Int'}} + $0 + 1.0 + // expected-error@+1 {{cannot convert value of type 'Double' to closure result type 'Int'}} } var closure6 = $0 // expected-error {{anonymous closure argument not contained in a closure}} diff --git a/test/expr/postfix/call/noescape-param-exclusivity-swift3.swift b/test/expr/postfix/call/noescape-param-exclusivity-swift3.swift new file mode 100644 index 00000000000..adefa90d2a0 --- /dev/null +++ b/test/expr/postfix/call/noescape-param-exclusivity-swift3.swift @@ -0,0 +1,5 @@ +// RUN: %target-typecheck-verify-swift -swift-version 3 + +func foo(fn: (() -> ()) -> ()) { + fn { fn {} } // expected-warning {{passing a closure which captures a non-escaping function parameter 'fn' to a call to a non-escaping function parameter can allow re-entrant modification of a variable and will be illegal in Swift 4}} +} diff --git a/test/expr/postfix/call/noescape-param-exclusivity.swift b/test/expr/postfix/call/noescape-param-exclusivity.swift new file mode 100644 index 00000000000..41af147b771 --- /dev/null +++ b/test/expr/postfix/call/noescape-param-exclusivity.swift @@ -0,0 +1,40 @@ +// RUN: %target-typecheck-verify-swift -swift-version 4 + +// FIXME: make these errors + +func test0(fn: (() -> ()) -> ()) { + fn { fn {} } // expected-warning {{passing a closure which captures a non-escaping function parameter 'fn' to a call to a non-escaping function parameter can allow re-entrant modification of a variable}} +} + +func test1(fn: (() -> ()) -> ()) { // expected-note {{parameter 'fn' is implicitly non-escaping}} + // TODO: infer that this function is noescape from its captures + func foo() { + fn { fn {} } // expected-warning {{can allow re-entrant modification}} + // expected-error@-1 {{declaration closing over non-escaping parameter 'fn' may allow it to escape}} + } +} + +func test2(x: inout Int, fn: (() -> ()) -> ()) { + func foo(myfn: () -> ()) { + x += 1 + myfn() + } + + // Make sure we only complain about calls to noescape parameters. + foo { fn {} } +} + +func test3(fn: (() -> ()) -> ()) { + { myfn in myfn { fn {} } }(fn) // expected-warning {{can allow re-entrant modification}} +} + +func test4(fn: (() -> ()) -> ()) { // expected-note {{parameter 'fn' is implicitly non-escaping}} + // TODO: infer that this function is noescape from its captures + func foo() { + fn {} + // expected-error@-1 {{declaration closing over non-escaping parameter 'fn' may allow it to escape}} + // FIXME: if the above is ever not an error, we should diagnose at the call below + } + + fn(foo) +} diff --git a/test/expr/unary/keypath/keypath-mutation.swift b/test/expr/unary/keypath/keypath-mutation.swift new file mode 100644 index 00000000000..9750dcd1fcf --- /dev/null +++ b/test/expr/unary/keypath/keypath-mutation.swift @@ -0,0 +1,22 @@ +// RUN: %target-swift-frontend -typecheck -verify %s + +struct User { + var id: Int + var name: String +} + +func setting(_ kp: WritableKeyPath, _ root: Root, _ value: Value) -> Root { + var copy = root + // Should not warn about lack of mutation + copy[keyPath: kp] = value + return copy +} + +func referenceSetting(_ kp: ReferenceWritableKeyPath, _ root: Root, _ value: Value) -> Root { + // Should warn about lack of mutation, since a RefKeyPath doesn't modify its + // base. + // expected-warning@+1 {{was never mutated}} + var copy = root + copy[keyPath: kp] = value + return copy +} diff --git a/test/expr/unary/keypath/keypath-unimplemented.swift b/test/expr/unary/keypath/keypath-unimplemented.swift index 1472987262a..b4fdaa3d388 100644 --- a/test/expr/unary/keypath/keypath-unimplemented.swift +++ b/test/expr/unary/keypath/keypath-unimplemented.swift @@ -10,11 +10,9 @@ class C { } func unsupportedComponents() { - _ = \A.c?.i // expected-error{{key path support for optional chaining components is not implemented}} - _ = \A.c!.i // expected-error{{key path support for optional force-unwrapping components is not implemented}} _ = \A.[0] // expected-error{{key path support for subscript components is not implemented}} } // rdar://problem/32209039 - Improve diagnostic when unsupported tuple element references are used in key path literals let _ = \(Int, String).0 // expected-error {{key path cannot reference tuple elements}} -let _ = \(a: Int, b: String).b // expected-error {{key path cannot reference tuple elements}} \ No newline at end of file +let _ = \(a: Int, b: String).b // expected-error {{key path cannot reference tuple elements}} diff --git a/test/expr/unary/keypath/keypath.swift b/test/expr/unary/keypath/keypath.swift index daa239e6533..882cd22065e 100644 --- a/test/expr/unary/keypath/keypath.swift +++ b/test/expr/unary/keypath/keypath.swift @@ -322,6 +322,20 @@ func testKeyPathSubscriptTuple(readonly: (Z,Z), writable: inout (Z,Z), writable[keyPath: rkp] = sink } +struct AA { + subscript(x: Int) -> Int { return x } + var c: CC? = CC() +} + +class CC { + var i = 0 +} + +func testKeyPathOptional() { + _ = \AA.c?.i + _ = \AA.c!.i +} + func testSyntaxErrors() { // expected-note{{}} // TODO: recovery _ = \. ; // expected-error{{expected member name following '.'}} diff --git a/test/lit.cfg b/test/lit.cfg index d7ce4c02d53..5578926521d 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -489,6 +489,16 @@ else: # Add substitutions for the run target triple, CPU, OS, and pointer size. config.substitutions.append(('%target-triple', config.variant_triple)) + +# Sanitizers are not supported on iOS7, yet all tests are configured to start +# testing with the earliest supported platform, which happens to be iOS7 for +# Swift. +# Setting target manually makes tests less versatile (a separate test is +# then required for each OS), thus instead we define a new environment +# variable which enforces the usage of iOS8+ when iOS is used. +config.substitutions.append(('%sanitizers-target-triple', + config.variant_triple.replace("ios7", "ios8"))) + config.substitutions.append(('%target-cpu', run_cpu)) config.substitutions.append(('%target-os', run_os)) config.substitutions.append(('%target-ptrsize', run_ptrsize)) @@ -843,6 +853,12 @@ else: "target_build_swift for platform " + config.variant_triple) +# Different OS's require different prefixes for the environment variables to be +# propagated to the calling contexts. +# In order to make tests OS-agnostic, names of environment variables should be +# prefixed with `%env-`, which is then expanded to the appropriate prefix. +ENV_VAR_PREFIXES = {'iphonesimulator': 'SIMCTL_CHILD_'} +config.substitutions.append(('%env-', ENV_VAR_PREFIXES.get(config.target_sdk_name, ""))) config.substitutions.append(("%target-sdk-name", config.target_sdk_name)) config.compiler_rt_libs = [] diff --git a/test/stdlib/CodableTests.swift b/test/stdlib/CodableTests.swift index feffa5accf8..242459612b2 100644 --- a/test/stdlib/CodableTests.swift +++ b/test/stdlib/CodableTests.swift @@ -11,6 +11,7 @@ // REQUIRES: objc_interop import Foundation +import CoreGraphics #if FOUNDATION_XCTEST import XCTest @@ -57,12 +58,21 @@ func expectRoundTripEquality(of value: T, encode: (T) throws -> Dat } func expectRoundTripEqualityThroughJSON(for value: T) where T : Equatable { + let inf = "INF", negInf = "-INF", nan = "NaN" let encode = { (_ value: T) throws -> Data in - return try JSONEncoder().encode(value) + let encoder = JSONEncoder() + encoder.nonConformingFloatEncodingStrategy = .convertToString(positiveInfinity: inf, + negativeInfinity: negInf, + nan: nan) + return try encoder.encode(value) } let decode = { (_ data: Data) throws -> T in - return try JSONDecoder().decode(T.self, from: data) + let decoder = JSONDecoder() + decoder.nonConformingFloatDecodingStrategy = .convertFromString(positiveInfinity: inf, + negativeInfinity: negInf, + nan: nan) + return try decoder.decode(T.self, from: data) } expectRoundTripEquality(of: value, encode: encode, decode: decode) @@ -186,6 +196,151 @@ class TestCodable : TestCodableSuper { } } + // MARK: - CGAffineTransform + lazy var cg_affineTransformValues: [CGAffineTransform] = { + var values = [ + CGAffineTransform.identity, + CGAffineTransform(), + CGAffineTransform(translationX: 2.0, y: 2.0), + CGAffineTransform(scaleX: 2.0, y: 2.0), + CGAffineTransform(a: 1.0, b: 2.5, c: 66.2, d: 40.2, tx: -5.5, ty: 3.7), + CGAffineTransform(a: -55.66, b: 22.7, c: 1.5, d: 0.0, tx: -22, ty: -33), + CGAffineTransform(a: 4.5, b: 1.1, c: 0.025, d: 0.077, tx: -0.55, ty: 33.2), + CGAffineTransform(a: 7.0, b: -2.3, c: 6.7, d: 0.25, tx: 0.556, ty: 0.99), + CGAffineTransform(a: 0.498, b: -0.284, c: -0.742, d: 0.3248, tx: 12, ty: 44) + ] + + if #available(OSX 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) { + values.append(CGAffineTransform(rotationAngle: .pi / 2)) + } + + return values + }() + + func test_CGAffineTransform_JSON() { + for transform in cg_affineTransformValues { + expectRoundTripEqualityThroughJSON(for: transform) + } + } + + func test_CGAffineTransform_Plist() { + for transform in cg_affineTransformValues { + expectRoundTripEqualityThroughPlist(for: transform) + } + } + + // MARK: - CGPoint + lazy var cg_pointValues: [CGPoint] = { + var values = [ + CGPoint.zero, + CGPoint(x: 10, y: 20) + ] + + if #available(OSX 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) { + // Limit on magnitude in JSON. See rdar://problem/12717407 + values.append(CGPoint(x: CGFloat.greatestFiniteMagnitude, + y: CGFloat.greatestFiniteMagnitude)) + } + + return values + }() + + func test_CGPoint_JSON() { + for point in cg_pointValues { + expectRoundTripEqualityThroughJSON(for: point) + } + } + + func test_CGPoint_Plist() { + for point in cg_pointValues { + expectRoundTripEqualityThroughPlist(for: point) + } + } + + // MARK: - CGSize + lazy var cg_sizeValues: [CGSize] = { + var values = [ + CGSize.zero, + CGSize(width: 30, height: 40) + ] + + if #available(OSX 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) { + // Limit on magnitude in JSON. See rdar://problem/12717407 + values.append(CGSize(width: CGFloat.greatestFiniteMagnitude, + height: CGFloat.greatestFiniteMagnitude)) + } + + return values + }() + + func test_CGSize_JSON() { + for size in cg_sizeValues { + expectRoundTripEqualityThroughJSON(for: size) + } + } + + func test_CGSize_Plist() { + for size in cg_sizeValues { + expectRoundTripEqualityThroughPlist(for: size) + } + } + + // MARK: - CGRect + lazy var cg_rectValues: [CGRect] = { + var values = [ + CGRect.zero, + CGRect.null, + CGRect(x: 10, y: 20, width: 30, height: 40) + ] + + if #available(OSX 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) { + // Limit on magnitude in JSON. See rdar://problem/12717407 + values.append(CGRect.infinite) + } + + return values + }() + + func test_CGRect_JSON() { + for rect in cg_rectValues { + expectRoundTripEqualityThroughJSON(for: rect) + } + } + + func test_CGRect_Plist() { + for rect in cg_rectValues { + expectRoundTripEqualityThroughPlist(for: rect) + } + } + + // MARK: - CGVector + lazy var cg_vectorValues: [CGVector] = { + var values = [ + CGVector.zero, + CGVector(dx: 0.0, dy: -9.81) + ] + + if #available(OSX 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) { + // Limit on magnitude in JSON. See rdar://problem/12717407 + values.append(CGVector(dx: CGFloat.greatestFiniteMagnitude, + dy: CGFloat.greatestFiniteMagnitude)) + } + + return values + }() + + func test_CGVector_JSON() { + for vector in cg_vectorValues { + expectRoundTripEqualityThroughJSON(for: vector) + } + } + + func test_CGVector_Plist() { + for vector in cg_vectorValues { + expectRoundTripEqualityThroughPlist(for: vector) + } + } + // MARK: - DateComponents lazy var dateComponents: Set = [ .era, .year, .month, .day, .hour, .minute, .second, .nanosecond, @@ -458,6 +613,16 @@ CodableTests.test("test_Calendar_JSON") { TestCodable().test_Calendar_JSON() } CodableTests.test("test_Calendar_Plist") { TestCodable().test_Calendar_Plist() } CodableTests.test("test_CharacterSet_JSON") { TestCodable().test_CharacterSet_JSON() } CodableTests.test("test_CharacterSet_Plist") { TestCodable().test_CharacterSet_Plist() } +CodableTests.test("test_CGAffineTransform_JSON") { TestCodable().test_CGAffineTransform_JSON() } +CodableTests.test("test_CGAffineTransform_Plist") { TestCodable().test_CGAffineTransform_Plist() } +CodableTests.test("test_CGPoint_JSON") { TestCodable().test_CGPoint_JSON() } +CodableTests.test("test_CGPoint_Plist") { TestCodable().test_CGPoint_Plist() } +CodableTests.test("test_CGSize_JSON") { TestCodable().test_CGSize_JSON() } +CodableTests.test("test_CGSize_Plist") { TestCodable().test_CGSize_Plist() } +CodableTests.test("test_CGRect_JSON") { TestCodable().test_CGRect_JSON() } +CodableTests.test("test_CGRect_Plist") { TestCodable().test_CGRect_Plist() } +CodableTests.test("test_CGVector_JSON") { TestCodable().test_CGVector_JSON() } +CodableTests.test("test_CGVector_Plist") { TestCodable().test_CGVector_Plist() } CodableTests.test("test_DateComponents_JSON") { TestCodable().test_DateComponents_JSON() } CodableTests.test("test_DateComponents_Plist") { TestCodable().test_DateComponents_Plist() } diff --git a/test/stdlib/Dispatch.swift b/test/stdlib/Dispatch.swift index 521f57c7a25..6d5ebc5dbe0 100644 --- a/test/stdlib/Dispatch.swift +++ b/test/stdlib/Dispatch.swift @@ -508,3 +508,12 @@ if #available(OSX 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) { expectTrue(result == .success) } } + +#if swift(>=4.0) +DispatchAPI.test("DispatchTimeInterval.never.equals") { + expectTrue(DispatchTimeInterval.never == DispatchTimeInterval.never) + expectTrue(DispatchTimeInterval.seconds(10) != DispatchTimeInterval.never); + expectTrue(DispatchTimeInterval.never != DispatchTimeInterval.seconds(10)); + expectTrue(DispatchTimeInterval.seconds(10) == DispatchTimeInterval.seconds(10)); +} +#endif diff --git a/test/stdlib/Intents.swift b/test/stdlib/Intents.swift index 2dab27fde30..495ef28124b 100644 --- a/test/stdlib/Intents.swift +++ b/test/stdlib/Intents.swift @@ -21,4 +21,21 @@ if #available(OSX 10.12, iOS 10.0, *) { } } +#if os(iOS) +if #available(iOS 11.0, *) { + + IntentsTestSuite.test("INParameter KeyPath") { + let param = INParameter(keyPath: \INRequestRideIntent.pickupLocation) + expectEqual("pickupLocation", param?.parameterKeyPath) + if let typ = param?.parameterClass { + expectEqual(INRequestRideIntent.self, typ) + } + else { + expectUnreachable() + } + } +} + +#endif + runAllTests() diff --git a/test/stdlib/KeyPath.swift b/test/stdlib/KeyPath.swift index c0dc2a02825..6ae9f094bca 100644 --- a/test/stdlib/KeyPath.swift +++ b/test/stdlib/KeyPath.swift @@ -346,4 +346,63 @@ keyPath.test("dynamically-typed application") { } } +struct TestOptional { + var origin: Point? + var questionableCanary: LifetimeTracked? = LifetimeTracked(123) + + init(origin: Point?) { + self.origin = origin + } +} + +keyPath.test("optional force-unwrapping") { + let origin_x = \TestOptional.origin!.x + let canary = \TestOptional.questionableCanary! + + var value = TestOptional(origin: Point(x: 3, y: 4)) + + expectEqual(value[keyPath: origin_x], 3) + expectEqual(value.origin!.x, 3) + + value[keyPath: origin_x] = 5 + + expectEqual(value[keyPath: origin_x], 5) + expectEqual(value.origin!.x, 5) + + expectTrue(value[keyPath: canary] === value.questionableCanary) + let newCanary = LifetimeTracked(456) + value[keyPath: canary] = newCanary + expectTrue(value[keyPath: canary] === newCanary) + expectTrue(value.questionableCanary === newCanary) +} + +keyPath.test("optional force-unwrapping trap") { + let origin_x = \TestOptional.origin!.x + var value = TestOptional(origin: nil) + + expectCrashLater() + _ = value[keyPath: origin_x] +} + +struct TestOptional2 { + var optional: TestOptional? +} + +keyPath.test("optional chaining") { + let origin_x = \TestOptional.origin?.x + let canary = \TestOptional.questionableCanary?.value + + let withPoint = TestOptional(origin: Point(x: 3, y: 4)) + expectEqual(withPoint[keyPath: origin_x]!, 3) + expectEqual(withPoint[keyPath: canary]!, 123) + + let withoutPoint = TestOptional(origin: nil) + expectNil(withoutPoint[keyPath: origin_x]) + + let optional2: TestOptional2? = TestOptional2(optional: withPoint) + let optional2_optional = \TestOptional2?.?.optional + expectEqual(optional2[keyPath: optional2_optional]!.origin!.x, 3) + expectEqual(optional2[keyPath: optional2_optional]!.origin!.y, 4) +} + runAllTests() diff --git a/test/stdlib/KeyPathImplementation.swift b/test/stdlib/KeyPathImplementation.swift index 70e9f1c1988..06ff84b6f30 100644 --- a/test/stdlib/KeyPathImplementation.swift +++ b/test/stdlib/KeyPathImplementation.swift @@ -135,20 +135,33 @@ struct TestKeyPathBuilder { } mutating func push(_ value: UInt32) { - assert(buffer.count >= 4, "not enough room") buffer.storeBytes(of: value, as: UInt32.self) buffer = .init(start: buffer.baseAddress! + 4, count: buffer.count - 4) } + mutating func push(_ value: Any.Type) { + var misalign = Int(bitPattern: buffer.baseAddress) % MemoryLayout.alignment + if misalign != 0 { + misalign = MemoryLayout.alignment - misalign + buffer = .init(start: buffer.baseAddress! + misalign, + count: buffer.count - misalign) + } + buffer.storeBytes(of: value, as: Any.Type.self) + buffer = .init(start: buffer.baseAddress! + MemoryLayout.size, + count: buffer.count - MemoryLayout.size) + } mutating func addHeader(trivial: Bool, hasReferencePrefix: Bool) { assert(state == .header, "not expecting a header") - let size = buffer.count - 4 + let size = buffer.count - MemoryLayout.size assert(buffer.count > 0 && buffer.count <= 0x3FFF_FFFF, "invalid buffer size") let header: UInt32 = UInt32(size) | (trivial ? 0x8000_0000 : 0) | (hasReferencePrefix ? 0x4000_0000 : 0) push(header) + if MemoryLayout.size == 8 { + push(0) + } self.hasReferencePrefix = hasReferencePrefix state.advance() } @@ -194,18 +207,7 @@ struct TestKeyPathBuilder { mutating func addType(_ type: Any.Type) { assert(state == .type, "not expecting a type") - if MemoryLayout.size == 8 { - // Components are 4-byte aligned, but pointers are 8-byte aligned, so - // we have to store word-by-word - let words = unsafeBitCast(type, to: (UInt32, UInt32).self) - push(words.0) - push(words.1) - } else if MemoryLayout.size == 4 { - let word = unsafeBitCast(type, to: UInt32.self) - push(word) - } else { - fatalError("unsupported architecture") - } + push(type) state.advance() } } @@ -223,30 +225,30 @@ extension AnyKeyPath { keyPathImpl.test("struct components") { let s_x = WritableKeyPath, Int> - .build(capacityInBytes: 8) { + .build(capacityInBytes: MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: false) $0.addStructComponent(offset: S.x_offset) } let s_y = WritableKeyPath, LifetimeTracked?> - .build(capacityInBytes: 8) { + .build(capacityInBytes: MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: false) $0.addStructComponent(offset: S.y_offset) } let s_z = WritableKeyPath, String> - .build(capacityInBytes: 8) { + .build(capacityInBytes: MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: false) $0.addStructComponent(offset: S.z_offset) } let s_p = WritableKeyPath, Point> - .build(capacityInBytes: 8) { + .build(capacityInBytes: MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: false) $0.addStructComponent(offset: S.p_offset) } - let twoComponentSize = 12 + MemoryLayout.size + let twoComponentSize = MemoryLayout.size * 3 + 4 let s_p_x = WritableKeyPath, Double> .build(capacityInBytes: twoComponentSize) { $0.addHeader(trivial: true, hasReferencePrefix: false) @@ -331,19 +333,19 @@ keyPathImpl.test("struct components") { keyPathImpl.test("class components") { let c_x = ReferenceWritableKeyPath, Int> - .build(capacityInBytes: 8) { + .build(capacityInBytes: MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: false) $0.addClassComponent(offset: C.x_offset) } let c_y = ReferenceWritableKeyPath, LifetimeTracked?> - .build(capacityInBytes: 8) { + .build(capacityInBytes: MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: false) $0.addClassComponent(offset: C.y_offset) } let c_z = ReferenceWritableKeyPath, String> - .build(capacityInBytes: 8) { + .build(capacityInBytes: MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: false) $0.addClassComponent(offset: C.z_offset) } @@ -394,7 +396,7 @@ keyPathImpl.test("class components") { keyPathImpl.test("reference prefix") { let s_c_x = ReferenceWritableKeyPath, Int> - .build(capacityInBytes: 12 + MemoryLayout.size) { + .build(capacityInBytes: 3 * MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: true) $0.addStructComponent(offset: S.c_offset, endsReferencePrefix: true) @@ -403,7 +405,7 @@ keyPathImpl.test("reference prefix") { } let s_c_y = ReferenceWritableKeyPath, LifetimeTracked?> - .build(capacityInBytes: 12 + MemoryLayout.size) { + .build(capacityInBytes: 3 * MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: true) $0.addStructComponent(offset: S.c_offset, endsReferencePrefix: true) @@ -412,7 +414,7 @@ keyPathImpl.test("reference prefix") { } let s_c_z = ReferenceWritableKeyPath, String> - .build(capacityInBytes: 12 + MemoryLayout.size) { + .build(capacityInBytes: 3 * MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: true) $0.addStructComponent(offset: S.c_offset, endsReferencePrefix: true) @@ -484,14 +486,14 @@ keyPathImpl.test("reference prefix") { keyPathImpl.test("overflowed offsets") { let s_p = WritableKeyPath, Point> - .build(capacityInBytes: 12) { + .build(capacityInBytes: MemoryLayout.size + 8) { $0.addHeader(trivial: true, hasReferencePrefix: false) $0.addStructComponent(offset: S.p_offset, forceOverflow: true) } let c_z = ReferenceWritableKeyPath, String> - .build(capacityInBytes: 12) { + .build(capacityInBytes: MemoryLayout.size + 8) { $0.addHeader(trivial: true, hasReferencePrefix: false) $0.addClassComponent(offset: C.z_offset, forceOverflow: true) @@ -516,7 +518,7 @@ keyPathImpl.test("overflowed offsets") { keyPathImpl.test("equality") { let s_c_z_p_x = ReferenceWritableKeyPath>, Double> - .build(capacityInBytes: 20 + 3 * MemoryLayout.size) { + .build(capacityInBytes: 7 * MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: true) // S>.c $0.addStructComponent(offset: S>.c_offset, @@ -537,7 +539,7 @@ keyPathImpl.test("equality") { // Structurally equivalent to s_c_z_p_x let s_c_z_p_x_2 = ReferenceWritableKeyPath>, Double> - .build(capacityInBytes: 20 + 3 * MemoryLayout.size) { + .build(capacityInBytes: 7 * MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: true) // S>.c $0.addStructComponent(offset: S>.c_offset, @@ -561,7 +563,7 @@ keyPathImpl.test("equality") { // Structurally equivalent, force-overflowed offset components let s_c_z_p_x_3 = ReferenceWritableKeyPath>, Double> - .build(capacityInBytes: 36 + 3 * MemoryLayout.size) { + .build(capacityInBytes: 4 * MemoryLayout.size + 4 * 8) { $0.addHeader(trivial: true, hasReferencePrefix: true) // S>.c $0.addStructComponent(offset: S>.c_offset, @@ -589,7 +591,7 @@ keyPathImpl.test("equality") { // Same path type, different suffixes let s_c_z_p_y = ReferenceWritableKeyPath>, Double> - .build(capacityInBytes: 20 + 3 * MemoryLayout.size) { + .build(capacityInBytes: 7 * MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: true) // S>.c $0.addStructComponent(offset: S>.c_offset, @@ -610,7 +612,7 @@ keyPathImpl.test("equality") { // Different path type let s_c_z_p = ReferenceWritableKeyPath>, Point> - .build(capacityInBytes: 16 + 2 * MemoryLayout.size) { + .build(capacityInBytes: 5 * MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: true) // S>.c $0.addStructComponent(offset: S>.c_offset, @@ -628,7 +630,7 @@ keyPathImpl.test("equality") { // Same path, no reference prefix let s_c_z_p_x_readonly = KeyPath>, Double> - .build(capacityInBytes: 20 + 3 * MemoryLayout.size) { + .build(capacityInBytes: 7 * MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: false) // S>.c $0.addStructComponent(offset: S>.c_offset) @@ -648,7 +650,7 @@ keyPathImpl.test("equality") { // Same path type, different paths let s_p_y_readonly = KeyPath>, Double> - .build(capacityInBytes: 12 + MemoryLayout.size) { + .build(capacityInBytes: 3 * MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: false) // S>.p $0.addStructComponent(offset: S>.p_offset) @@ -661,7 +663,7 @@ keyPathImpl.test("equality") { expectNotEqual(s_c_z_p_x_readonly, s_p_y_readonly) let o_o_o_o = ReferenceWritableKeyPath - .build(capacityInBytes: 16 + 2*MemoryLayout.size) { + .build(capacityInBytes: 5 * MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: false) // O.o $0.addClassComponent(offset: classHeaderSize) @@ -675,7 +677,7 @@ keyPathImpl.test("equality") { // Different reference prefix length let o_o_o_o_rp1 = ReferenceWritableKeyPath - .build(capacityInBytes: 16 + 2*MemoryLayout.size) { + .build(capacityInBytes: 5 * MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: true) // O.o $0.addClassComponent(offset: classHeaderSize, @@ -688,7 +690,7 @@ keyPathImpl.test("equality") { $0.addClassComponent(offset: classHeaderSize) } let o_o_o_o_rp2 = ReferenceWritableKeyPath - .build(capacityInBytes: 16 + 2*MemoryLayout.size) { + .build(capacityInBytes: 5 * MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: true) // O.o $0.addClassComponent(offset: classHeaderSize) @@ -701,7 +703,7 @@ keyPathImpl.test("equality") { $0.addClassComponent(offset: classHeaderSize) } let o_o_o_o_rp2_2 = ReferenceWritableKeyPath - .build(capacityInBytes: 16 + 2*MemoryLayout.size) { + .build(capacityInBytes: 5 * MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: true) // O.o $0.addClassComponent(offset: classHeaderSize) @@ -729,7 +731,7 @@ keyPathImpl.test("equality") { // Same type, different length of components with same prefix let o_o_o = ReferenceWritableKeyPath - .build(capacityInBytes: 12 + MemoryLayout.size) { + .build(capacityInBytes: 3 * MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: false) // O.o $0.addClassComponent(offset: classHeaderSize) @@ -744,12 +746,12 @@ keyPathImpl.test("equality") { keyPathImpl.test("appending") { let s_p = WritableKeyPath, Point> - .build(capacityInBytes: 8) { + .build(capacityInBytes: MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: false) $0.addStructComponent(offset: S.p_offset) } let p_y = WritableKeyPath - .build(capacityInBytes: 8) { + .build(capacityInBytes: MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: false) $0.addStructComponent(offset: Point.y_offset) } @@ -772,7 +774,7 @@ keyPathImpl.test("appending") { expectEqual(s_p_y.hashValue, s_p_y2.hashValue) let s_p_y_manual = WritableKeyPath, Double> - .build(capacityInBytes: 12 + MemoryLayout.size) { + .build(capacityInBytes: 3 * MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: false) $0.addStructComponent(offset: S.p_offset) $0.addType(Point.self) @@ -783,7 +785,7 @@ keyPathImpl.test("appending") { expectEqual(s_p_y.hashValue, s_p_y_manual.hashValue) let c_z = ReferenceWritableKeyPath>, S> - .build(capacityInBytes: 8) { + .build(capacityInBytes: MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: false) $0.addClassComponent(offset: C>.z_offset) } @@ -799,7 +801,7 @@ keyPathImpl.test("appending") { expectEqual(value2.z.p.x, 0.5) let c_z_p_y_manual = ReferenceWritableKeyPath>, Double> - .build(capacityInBytes: 16 + MemoryLayout.size * 2) { + .build(capacityInBytes: 5 * MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: false) $0.addClassComponent(offset: C>.z_offset) $0.addType(S.self) @@ -813,7 +815,7 @@ keyPathImpl.test("appending") { expectEqual(c_z_p_y.hashValue, c_z_p_y_manual.hashValue) let s_c = WritableKeyPath>, C>> - .build(capacityInBytes: 8) { + .build(capacityInBytes: MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: false) $0.addStructComponent(offset: S>.c_offset) } @@ -828,7 +830,7 @@ keyPathImpl.test("appending") { expectEqual(value2[keyPath: c_z_p_y], 11.0) let s_c_z_p_y_manual = ReferenceWritableKeyPath>, Double> - .build(capacityInBytes: 20 + MemoryLayout.size * 3) { + .build(capacityInBytes: 7 * MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: true) $0.addStructComponent(offset: S>.c_offset, endsReferencePrefix: true) @@ -846,7 +848,7 @@ keyPathImpl.test("appending") { typealias CP = CratePair>, Int> let cratePair_left_value = ReferenceWritableKeyPath>> - .build(capacityInBytes: 12 + MemoryLayout.size) { + .build(capacityInBytes: 3 * MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: true) $0.addStructComponent(offset: CratePair>, Int>.left_offset, endsReferencePrefix: true) @@ -868,7 +870,7 @@ keyPathImpl.test("appending") { let cratePair_left_value_c_z_p_y_manual = ReferenceWritableKeyPath - .build(capacityInBytes: 28 + 5*MemoryLayout.size) { + .build(capacityInBytes: 11 * MemoryLayout.size + 4) { $0.addHeader(trivial: true, hasReferencePrefix: true) $0.addStructComponent(offset: CP.left_offset) $0.addType(Crate>>.self) diff --git a/test/stdlib/KeyPathObjC.swift b/test/stdlib/KeyPathObjC.swift index 89383a55cce..aface862076 100644 --- a/test/stdlib/KeyPathObjC.swift +++ b/test/stdlib/KeyPathObjC.swift @@ -22,12 +22,34 @@ class Foo: NSObject { @objc subscript(x: Bar) -> Foo { return self } dynamic var dynamic: Bar { fatalError() } + + let storedLet = LifetimeTracked(0) +} + +// We just need some non-empty ObjC-defined class here to ensure we get the +// right offset for a 'let' or final stored property after the ObjC runtime +// slides offsets +class MyWeirdFormatter: DateFormatter { + let storedLet = LifetimeTracked(1) } class Bar: NSObject { @objc var foo: Foo { fatalError() } } +var testStoredProperties = TestSuite("stored properties in ObjC subclasses") + +testStoredProperties.test("final stored properties in ObjC subclasses") { + let fooLet = \Foo.storedLet + let formatterLet = \MyWeirdFormatter.storedLet + + let foo = Foo() + let formatter = MyWeirdFormatter() + + expectTrue(foo[keyPath: fooLet] === foo.storedLet) + expectTrue(formatter[keyPath: formatterLet] === formatter.storedLet) +} + var testKVCStrings = TestSuite("KVC strings") testKVCStrings.test("KVC strings") { diff --git a/test/stdlib/NSError.swift b/test/stdlib/NSError.swift index 85fb91e084e..26f0461e35e 100644 --- a/test/stdlib/NSError.swift +++ b/test/stdlib/NSError.swift @@ -53,4 +53,9 @@ tests.test("convenience") { expectEqual("bar", (error3 as NSError).userInfo["foo"] as? String) } +tests.test("Hashable") { + checkHashable([CocoaError.Code.fileNoSuchFile, .fileReadUnknown, .keyValueValidation], equalityOracle: { $0 == $1 }) + checkHashable([URLError.Code.unknown, .cancelled, .badURL], equalityOracle: { $0 == $1 }) +} + runAllTests() diff --git a/test/stdlib/StringFlatMap.swift b/test/stdlib/StringFlatMap.swift index 82d8cd03b79..67439ec1ab2 100644 --- a/test/stdlib/StringFlatMap.swift +++ b/test/stdlib/StringFlatMap.swift @@ -7,28 +7,30 @@ import StdlibUnittest #if swift(>=4) public typealias ExpectedResultType = [Character] +let swiftVersion = "4" #else public typealias ExpectedResultType = [String] +let swiftVersion = "3" #endif var Tests = TestSuite("StringFlatMap") -Tests.test("DefaultReturnType") { +Tests.test("DefaultReturnType/\(swiftVersion)") { var result = ["hello", "world"].flatMap { $0 } expectType(ExpectedResultType.self, &result) } -Tests.test("ExplicitTypeContext") { +Tests.test("ExplicitTypeContext/\(swiftVersion)") { expectEqualSequence(["hello", "world"], ["hello", "world"].flatMap { $0 } as [String]) expectEqualSequence("helloworld".characters, ["hello", "world"].flatMap { $0 } as [Character]) } -Tests.test("inference") { +Tests.test("inference/\(swiftVersion)") { let result = [1, 2].flatMap { x in if String(x) == "foo" { return "bar" diff --git a/test/stdlib/TestData.swift b/test/stdlib/TestData.swift index efe8e08bff3..55297fa4d77 100644 --- a/test/stdlib/TestData.swift +++ b/test/stdlib/TestData.swift @@ -1072,6 +1072,70 @@ class TestData : TestDataSuper { let actual = d2.map { $0 } expectEqual(expected, actual) } + + func test_dropFirst() { + var data = Data([0, 1, 2, 3, 4, 5]) + let sliced = data.dropFirst() + expectEqual(data.count - 1, sliced.count) + expectEqual(UInt8(1), sliced[1]) + expectEqual(UInt8(2), sliced[2]) + expectEqual(UInt8(3), sliced[3]) + expectEqual(UInt8(4), sliced[4]) + expectEqual(UInt8(5), sliced[5]) + } + + func test_dropFirst2() { + var data = Data([0, 1, 2, 3, 4, 5]) + let sliced = data.dropFirst(2) + expectEqual(data.count - 2, sliced.count) + expectEqual(UInt8(2), sliced[2]) + expectEqual(UInt8(3), sliced[3]) + expectEqual(UInt8(4), sliced[4]) + expectEqual(UInt8(5), sliced[5]) + } + + func test_copyBytes1() { + var array: [UInt8] = [0, 1, 2, 3] + var data = Data(bytes: array) + + array.withUnsafeMutableBufferPointer { + data[1..<3].copyBytes(to: $0.baseAddress!, from: 1..<3) + } + expectEqual([UInt8(1), UInt8(2), UInt8(2), UInt8(3)], array) + } + + func test_copyBytes2() { + let array: [UInt8] = [0, 1, 2, 3] + var data = Data(bytes: array) + + let expectedSlice = array[1..<3] + + let start = data.index(after: data.startIndex) + let end = data.index(before: data.endIndex) + let slice = data[start.. Date in return timestamp } // We can't encode a top-level Date, so it'll be wrapped in an array. - let expectedJSON = "[42]".data(using: .utf8)! + let expectedJSON = "{\"value\":42}".data(using: .utf8)! _testRoundTrip(of: TopLevelWrapper(timestamp), expectedJSON: expectedJSON, dateEncodingStrategy: .custom(encode), @@ -202,7 +208,7 @@ class TestJSONEncoder : TestJSONEncoderSuper { let decode = { (_: Decoder) throws -> Date in return timestamp } // We can't encode a top-level Date, so it'll be wrapped in an array. - let expectedJSON = "[{}]".data(using: .utf8)! + let expectedJSON = "{\"value\":{}}".data(using: .utf8)! _testRoundTrip(of: TopLevelWrapper(timestamp), expectedJSON: expectedJSON, dateEncodingStrategy: .custom(encode), @@ -214,7 +220,7 @@ class TestJSONEncoder : TestJSONEncoderSuper { let data = Data(bytes: [0xDE, 0xAD, 0xBE, 0xEF]) // We can't encode a top-level Data, so it'll be wrapped in an array. - let expectedJSON = "[\"3q2+7w==\"]".data(using: .utf8)! + let expectedJSON = "{\"value\":\"3q2+7w==\"}".data(using: .utf8)! _testRoundTrip(of: TopLevelWrapper(data), expectedJSON: expectedJSON) } @@ -227,7 +233,7 @@ class TestJSONEncoder : TestJSONEncoderSuper { let decode = { (_: Decoder) throws -> Data in return Data() } // We can't encode a top-level Data, so it'll be wrapped in an array. - let expectedJSON = "[42]".data(using: .utf8)! + let expectedJSON = "{\"value\":42}".data(using: .utf8)! _testRoundTrip(of: TopLevelWrapper(Data()), expectedJSON: expectedJSON, dataEncodingStrategy: .custom(encode), @@ -240,7 +246,7 @@ class TestJSONEncoder : TestJSONEncoderSuper { let decode = { (_: Decoder) throws -> Data in return Data() } // We can't encode a top-level Data, so it'll be wrapped in an array. - let expectedJSON = "[{}]".data(using: .utf8)! + let expectedJSON = "{\"value\":{}}".data(using: .utf8)! _testRoundTrip(of: TopLevelWrapper(Data()), expectedJSON: expectedJSON, dataEncodingStrategy: .custom(encode), @@ -264,32 +270,32 @@ class TestJSONEncoder : TestJSONEncoderSuper { _testRoundTrip(of: TopLevelWrapper(Float.infinity), - expectedJSON: "[\"INF\"]".data(using: .utf8)!, + expectedJSON: "{\"value\":\"INF\"}".data(using: .utf8)!, nonConformingFloatEncodingStrategy: encodingStrategy, nonConformingFloatDecodingStrategy: decodingStrategy) _testRoundTrip(of: TopLevelWrapper(-Float.infinity), - expectedJSON: "[\"-INF\"]".data(using: .utf8)!, + expectedJSON: "{\"value\":\"-INF\"}".data(using: .utf8)!, nonConformingFloatEncodingStrategy: encodingStrategy, nonConformingFloatDecodingStrategy: decodingStrategy) // Since Float.nan != Float.nan, we have to use a placeholder that'll encode NaN but actually round-trip. _testRoundTrip(of: TopLevelWrapper(FloatNaNPlaceholder()), - expectedJSON: "[\"NaN\"]".data(using: .utf8)!, + expectedJSON: "{\"value\":\"NaN\"}".data(using: .utf8)!, nonConformingFloatEncodingStrategy: encodingStrategy, nonConformingFloatDecodingStrategy: decodingStrategy) _testRoundTrip(of: TopLevelWrapper(Double.infinity), - expectedJSON: "[\"INF\"]".data(using: .utf8)!, + expectedJSON: "{\"value\":\"INF\"}".data(using: .utf8)!, nonConformingFloatEncodingStrategy: encodingStrategy, nonConformingFloatDecodingStrategy: decodingStrategy) _testRoundTrip(of: TopLevelWrapper(-Double.infinity), - expectedJSON: "[\"-INF\"]".data(using: .utf8)!, + expectedJSON: "{\"value\":\"-INF\"}".data(using: .utf8)!, nonConformingFloatEncodingStrategy: encodingStrategy, nonConformingFloatDecodingStrategy: decodingStrategy) // Since Double.nan != Double.nan, we have to use a placeholder that'll encode NaN but actually round-trip. _testRoundTrip(of: TopLevelWrapper(DoubleNaNPlaceholder()), - expectedJSON: "[\"NaN\"]".data(using: .utf8)!, + expectedJSON: "{\"value\":\"NaN\"}".data(using: .utf8)!, nonConformingFloatEncodingStrategy: encodingStrategy, nonConformingFloatDecodingStrategy: decodingStrategy) } @@ -313,6 +319,22 @@ class TestJSONEncoder : TestJSONEncoderSuper { } } + func testInterceptDecimal() { + let expectedJSON = "{\"value\":10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000}".data(using: .utf8)! + + // Want to make sure we write out a JSON number, not the keyed encoding here. + // 1e127 is too big to fit natively in a Double, too, so want to make sure it's encoded as a Decimal. + let decimal = Decimal(sign: .plus, exponent: 127, significand: Decimal(1)) + _testRoundTrip(of: TopLevelWrapper(decimal), expectedJSON: expectedJSON) + } + + func testInterceptURL() { + // Want to make sure JSONEncoder writes out single-value URLs, not the keyed encoding. + let expectedJSON = "{\"value\":\"http:\\/\\/swift.org\"}".data(using: .utf8)! + let url = URL(string: "http://swift.org")! + _testRoundTrip(of: TopLevelWrapper(url), expectedJSON: expectedJSON) + } + // MARK: - Helper Functions private var _jsonEmptyDictionary: Data { return "{}".data(using: .utf8)! @@ -527,10 +549,6 @@ fileprivate struct Address : Codable, Equatable { fileprivate class Person : Codable, Equatable { let name: String let email: String - - // FIXME: This property is present only in order to test the expected result of Codable synthesis in the compiler. - // We want to test against expected encoded output (to ensure this generates an encodeIfPresent call), but we need an output format for that. - // Once we have a VerifyingEncoder for compiler unit tests, we should move this test there. let website: URL? init(name: String, email: String, website: URL? = nil) { @@ -539,23 +557,86 @@ fileprivate class Person : Codable, Equatable { self.website = website } - static func ==(_ lhs: Person, _ rhs: Person) -> Bool { - return lhs.name == rhs.name && - lhs.email == rhs.email && - lhs.website == rhs.website + private enum CodingKeys : String, CodingKey { + case name + case email + case website } - static var testValue: Person { + // FIXME: Remove when subclasses (Employee) are able to override synthesized conformance. + required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + name = try container.decode(String.self, forKey: .name) + email = try container.decode(String.self, forKey: .email) + website = try container.decodeIfPresent(URL.self, forKey: .website) + } + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(name, forKey: .name) + try container.encode(email, forKey: .email) + try container.encodeIfPresent(website, forKey: .website) + } + + func isEqual(_ other: Person) -> Bool { + return self.name == other.name && + self.email == other.email && + self.website == other.website + } + + static func ==(_ lhs: Person, _ rhs: Person) -> Bool { + return lhs.isEqual(rhs) + } + + class var testValue: Person { return Person(name: "Johnny Appleseed", email: "appleseed@apple.com") } } +/// A class which shares its encoder and decoder with its superclass. +fileprivate class Employee : Person { + let id: Int + + init(name: String, email: String, website: URL? = nil, id: Int) { + self.id = id + super.init(name: name, email: email, website: website) + } + + enum CodingKeys : String, CodingKey { + case id + } + + required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + id = try container.decode(Int.self, forKey: .id) + try super.init(from: decoder) + } + + override func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(id, forKey: .id) + try super.encode(to: encoder) + } + + override func isEqual(_ other: Person) -> Bool { + if let employee = other as? Employee { + guard self.id == employee.id else { return false } + } + + return super.isEqual(other) + } + + override class var testValue: Employee { + return Employee(name: "Johnny Appleseed", email: "appleseed@apple.com", id: 42) + } +} + /// A simple company struct which encodes as a dictionary of nested values. fileprivate struct Company : Codable, Equatable { let address: Address - var employees: [Person] + var employees: [Employee] - init(address: Address, employees: [Person]) { + init(address: Address, employees: [Employee]) { self.address = address self.employees = employees } @@ -565,7 +646,7 @@ fileprivate struct Company : Codable, Equatable { } static var testValue: Company { - return Company(address: Address.testValue, employees: [Person.testValue]) + return Company(address: Address.testValue, employees: [Employee.testValue]) } } @@ -579,17 +660,6 @@ fileprivate struct TopLevelWrapper : Codable, Equatable where T : Codable, T self.value = value } - func encode(to encoder: Encoder) throws { - var container = encoder.unkeyedContainer() - try container.encode(value) - } - - init(from decoder: Decoder) throws { - var container = try decoder.unkeyedContainer() - value = try container.decode(T.self) - assert(container.isAtEnd) - } - static func ==(_ lhs: TopLevelWrapper, _ rhs: TopLevelWrapper) -> Bool { return lhs.value == rhs.value } @@ -797,6 +867,7 @@ JSONEncoderTests.test("testEncodingTopLevelStructuredClass") { TestJSONEncoder() JSONEncoderTests.test("testEncodingTopLevelStructuredSingleStruct") { TestJSONEncoder().testEncodingTopLevelStructuredSingleStruct() } JSONEncoderTests.test("testEncodingTopLevelStructuredSingleClass") { TestJSONEncoder().testEncodingTopLevelStructuredSingleClass() } JSONEncoderTests.test("testEncodingTopLevelDeepStructuredType") { TestJSONEncoder().testEncodingTopLevelDeepStructuredType()} +JSONEncoderTests.test("testEncodingClassWhichSharesEncoderWithSuper") { TestJSONEncoder().testEncodingClassWhichSharesEncoderWithSuper() } JSONEncoderTests.test("testEncodingOutputFormattingDefault") { TestJSONEncoder().testEncodingOutputFormattingDefault() } JSONEncoderTests.test("testEncodingOutputFormattingPrettyPrinted") { TestJSONEncoder().testEncodingOutputFormattingPrettyPrinted() } JSONEncoderTests.test("testEncodingOutputFormattingSortedKeys") { TestJSONEncoder().testEncodingOutputFormattingSortedKeys() } @@ -815,5 +886,7 @@ JSONEncoderTests.test("testEncodingNonConformingFloats") { TestJSONEncoder().tes JSONEncoderTests.test("testEncodingNonConformingFloatStrings") { TestJSONEncoder().testEncodingNonConformingFloatStrings() } JSONEncoderTests.test("testNestedContainerCodingPaths") { TestJSONEncoder().testNestedContainerCodingPaths() } JSONEncoderTests.test("testSuperEncoderCodingPaths") { TestJSONEncoder().testSuperEncoderCodingPaths() } +JSONEncoderTests.test("testInterceptDecimal") { TestJSONEncoder().testInterceptDecimal() } +JSONEncoderTests.test("testInterceptURL") { TestJSONEncoder().testInterceptURL() } runAllTests() #endif diff --git a/test/stdlib/TestNSNumberBridging.swift b/test/stdlib/TestNSNumberBridging.swift index 5bb04d3a8fb..27b04fc9725 100644 --- a/test/stdlib/TestNSNumberBridging.swift +++ b/test/stdlib/TestNSNumberBridging.swift @@ -18,6 +18,58 @@ import StdlibUnittest import Foundation import CoreGraphics +extension Float { + init?(reasonably value: Float) { + self = value + } + + init?(reasonably value: Double) { + guard !value.isNaN else { + self = Float.nan + return + } + + guard !value.isInfinite else { + if value.sign == .minus { + self = -Float.infinity + } else { + self = Float.infinity + } + return + } + + guard abs(value) <= Double(Float.greatestFiniteMagnitude) else { + return nil + } + + self = Float(value) + } +} + +extension Double { + init?(reasonably value: Float) { + guard !value.isNaN else { + self = Double.nan + return + } + + guard !value.isInfinite else { + if value.sign == .minus { + self = -Double.infinity + } else { + self = Double.infinity + } + return + } + + self = Double(value) + } + + init?(reasonably value: Double) { + self = value + } +} + var nsNumberBridging = TestSuite("NSNumberBridging") func testFloat(_ lhs: Float?, _ rhs: Float?, file: String = #file, line: UInt = #line) { @@ -645,7 +697,7 @@ func testNSNumberBridgeFromFloat() { expectEqual(UInt(exactly: interestingValue), uint) let float = (number!) as? Float - let expectedFloat = Float(exactly: interestingValue) + let expectedFloat = Float(reasonably: interestingValue) testFloat(expectedFloat, float) let double = (number!) as? Double @@ -685,7 +737,7 @@ func testNSNumberBridgeFromDouble() { expectEqual(UInt(exactly: interestingValue), uint) let float = (number!) as? Float - let expectedFloat = Float(exactly: interestingValue) + let expectedFloat = Float(reasonably: interestingValue) testFloat(expectedFloat, float) let double = (number!) as? Double @@ -725,7 +777,7 @@ func testNSNumberBridgeFromCGFloat() { expectEqual(UInt(exactly: interestingValue.native), uint) let float = (number!) as? Float - let expectedFloat = Float(exactly: interestingValue.native) + let expectedFloat = Float(reasonably: interestingValue.native) testFloat(expectedFloat, float) let double = (number!) as? Double diff --git a/test/stdlib/TestNSRange.swift b/test/stdlib/TestNSRange.swift new file mode 100644 index 00000000000..0d49866ba92 --- /dev/null +++ b/test/stdlib/TestNSRange.swift @@ -0,0 +1,160 @@ +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// RUN: %target-run-simple-swift +// REQUIRES: executable_test +// REQUIRES: objc_interop + +import Foundation + +#if FOUNDATION_XCTEST +import XCTest +class TestNSRangeSuper : XCTestCase { } +#else +import StdlibUnittest +class TestNSRangeSuper { } +#endif + +class TestNSRange : TestNSRangeSuper { + func testEquality() { + let r1 = NSRange(location: 1, length: 10) + let r2 = NSRange(location: 1, length: 11) + let r3 = NSRange(location: 2, length: 10) + let r4 = NSRange(location: 1, length: 10) + let r5 = NSRange(location: NSNotFound, length: 0) + let r6 = NSRange(location: NSNotFound, length: 2) + + expectNotEqual(r1, r2) + expectNotEqual(r1, r3) + expectEqual(r1, r4) + expectNotEqual(r1, r5) + expectNotEqual(r5, r6) + } + + func testDescription() { + let r1 = NSRange(location: 0, length: 22) + let r2 = NSRange(location: 10, length: 22) + let r3 = NSRange(location: NSNotFound, length: 0) + let r4 = NSRange(location: NSNotFound, length: 22) + expectEqual("{0, 22}", r1.description) + expectEqual("{10, 22}", r2.description) + expectEqual("{\(NSNotFound), 0}", r3.description) + expectEqual("{\(NSNotFound), 22}", r4.description) + + expectEqual("{0, 22}", r1.debugDescription) + expectEqual("{10, 22}", r2.debugDescription) + expectEqual("{NSNotFound, 0}", r3.debugDescription) + expectEqual("{NSNotFound, 22}", r4.debugDescription) + } + + func testCreationFromString() { + let r1 = NSRange("") + expectNil(r1) + let r2 = NSRange("1") + expectNil(r2) + let r3 = NSRange("1 2") + expectEqual(NSRange(location: 1, length: 2), r3) + let r4 = NSRange("{1 8") + expectEqual(NSRange(location: 1, length: 8), r4) + let r5 = NSRange("1.8") + expectNil(r5) + let r6 = NSRange("1-9") + expectEqual(NSRange(location: 1, length: 9), r6) + let r7 = NSRange("{1,9}") + expectEqual(NSRange(location: 1, length: 9), r7) + let r8 = NSRange("{1,9}asdfasdf") + expectEqual(NSRange(location: 1, length: 9), r8) + let r9 = NSRange("{1,9}{2,7}") + expectEqual(NSRange(location: 1, length: 9), r9) + let r10 = NSRange("{1,9}") + expectEqual(NSRange(location: 1, length: 9), r10) + let r11 = NSRange("{1.0,9}") + expectEqual(NSRange(location: 1, length: 9), r11) + let r12 = NSRange("{1,9.0}") + expectEqual(NSRange(location: 1, length: 9), r12) + let r13 = NSRange("{1.2,9}") + expectNil(r13) + let r14 = NSRange("{1,9.8}") + expectNil(r14) + } + + func testHashing() { + let r1 = NSRange(location: 10, length: 22) + let r2 = NSRange(location: 10, length: 22) + let r3 = NSRange(location: 1, length: 22) + expectEqual(r1.hashValue, r2.hashValue) + expectNotEqual(r1.hashValue, r3.hashValue) + let rangeSet: Set = [r1, r2, r3] + expectEqual(2, rangeSet.count) + } + + func testBounding() { + let r1 = NSRange(location: 1000, length: 2222) + expectEqual(r1.location, r1.lowerBound) + expectEqual(r1.location + r1.length, r1.upperBound) + } + + func testContains() { + let r1 = NSRange(location: 1000, length: 2222) + expectFalse(r1.contains(3)) + expectTrue(r1.contains(1001)) + expectFalse(r1.contains(4000)) + } + + func testUnion() { + let r1 = NSRange(location: 10, length: 20) + let r2 = NSRange(location: 30, length: 5) + let union1 = r1.union(r2) + + expectEqual(Swift.min(r1.lowerBound, r2.lowerBound), union1.lowerBound) + expectEqual(Swift.max(r1.upperBound, r2.upperBound), union1.upperBound) + + let r3 = NSRange(location: 10, length: 20) + let r4 = NSRange(location: 11, length: 5) + let union2 = r3.union(r4) + + expectEqual(Swift.min(r3.lowerBound, r4.lowerBound), union2.lowerBound) + expectEqual(Swift.max(r3.upperBound, r4.upperBound), union2.upperBound) + + let r5 = NSRange(location: 10, length: 20) + let r6 = NSRange(location: 11, length: 29) + let union3 = r5.union(r6) + + expectEqual(Swift.min(r5.lowerBound, r6.upperBound), union3.lowerBound) + expectEqual(Swift.max(r5.upperBound, r6.upperBound), union3.upperBound) + } + + func testIntersection() { + let r1 = NSRange(location: 1, length: 7) + let r2 = NSRange(location: 2, length: 20) + let r3 = NSRange(location: 2, length: 2) + let r4 = NSRange(location: 10, length: 7) + + let intersection1 = r1.intersection(r2) + expectEqual(NSRange(location: 2, length: 6), intersection1) + let intersection2 = r1.intersection(r3) + expectEqual(NSRange(location: 2, length: 2), intersection2) + let intersection3 = r1.intersection(r4) + expectEqual(nil, intersection3) + } +} + +#if !FOUNDATION_XCTEST +var NSRangeTests = TestSuite("TestNSRange") + +NSRangeTests.test("testEquality") { TestNSRange().testEquality() } +NSRangeTests.test("testDescription") { TestNSRange().testDescription() } +NSRangeTests.test("testCreationFromString") { TestNSRange().testCreationFromString() } +NSRangeTests.test("testHashing") { TestNSRange().testHashing() } +NSRangeTests.test("testBounding") { TestNSRange().testBounding() } +NSRangeTests.test("testContains") { TestNSRange().testContains() } +NSRangeTests.test("testUnion") { TestNSRange().testUnion() } +NSRangeTests.test("testIntersection") { TestNSRange().testIntersection() } + +runAllTests() +#endif diff --git a/test/stdlib/TestPlistEncoder.swift b/test/stdlib/TestPlistEncoder.swift index 85b87e8e741..2ae63774be5 100644 --- a/test/stdlib/TestPlistEncoder.swift +++ b/test/stdlib/TestPlistEncoder.swift @@ -104,6 +104,13 @@ class TestPropertyListEncoder : TestPropertyListEncoderSuper { _testRoundTrip(of: company, in: .xml) } + func testEncodingClassWhichSharesEncoderWithSuper() { + // Employee is a type which shares its encoder & decoder with its superclass, Person. + let employee = Employee.testValue + _testRoundTrip(of: employee, in: .binary) + _testRoundTrip(of: employee, in: .xml) + } + // MARK: - Encoder Features func testNestedContainerCodingPaths() { let encoder = JSONEncoder() @@ -330,27 +337,94 @@ fileprivate struct Address : Codable, Equatable { fileprivate class Person : Codable, Equatable { let name: String let email: String + let website: URL? - init(name: String, email: String) { + init(name: String, email: String, website: URL? = nil) { self.name = name self.email = email + self.website = website + } + + private enum CodingKeys : String, CodingKey { + case name + case email + case website + } + + // FIXME: Remove when subclasses (Employee) are able to override synthesized conformance. + required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + name = try container.decode(String.self, forKey: .name) + email = try container.decode(String.self, forKey: .email) + website = try container.decodeIfPresent(URL.self, forKey: .website) + } + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(name, forKey: .name) + try container.encode(email, forKey: .email) + try container.encodeIfPresent(website, forKey: .website) + } + + func isEqual(_ other: Person) -> Bool { + return self.name == other.name && + self.email == other.email && + self.website == other.website } static func ==(_ lhs: Person, _ rhs: Person) -> Bool { - return lhs.name == rhs.name && lhs.email == rhs.email + return lhs.isEqual(rhs) } - static var testValue: Person { + class var testValue: Person { return Person(name: "Johnny Appleseed", email: "appleseed@apple.com") } } +/// A class which shares its encoder and decoder with its superclass. +fileprivate class Employee : Person { + let id: Int + + init(name: String, email: String, website: URL? = nil, id: Int) { + self.id = id + super.init(name: name, email: email, website: website) + } + + enum CodingKeys : String, CodingKey { + case id + } + + required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + id = try container.decode(Int.self, forKey: .id) + try super.init(from: decoder) + } + + override func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(id, forKey: .id) + try super.encode(to: encoder) + } + + override func isEqual(_ other: Person) -> Bool { + if let employee = other as? Employee { + guard self.id == employee.id else { return false } + } + + return super.isEqual(other) + } + + override class var testValue: Employee { + return Employee(name: "Johnny Appleseed", email: "appleseed@apple.com", id: 42) + } +} + /// A simple company struct which encodes as a dictionary of nested values. fileprivate struct Company : Codable, Equatable { let address: Address - var employees: [Person] + var employees: [Employee] - init(address: Address, employees: [Person]) { + init(address: Address, employees: [Employee]) { self.address = address self.employees = employees } @@ -360,7 +434,7 @@ fileprivate struct Company : Codable, Equatable { } static var testValue: Company { - return Company(address: Address.testValue, employees: [Person.testValue]) + return Company(address: Address.testValue, employees: [Employee.testValue]) } } @@ -520,17 +594,6 @@ fileprivate struct TopLevelWrapper : Codable, Equatable where T : Codable, T self.value = value } - func encode(to encoder: Encoder) throws { - var container = encoder.unkeyedContainer() - try container.encode(value) - } - - init(from decoder: Decoder) throws { - var container = try decoder.unkeyedContainer() - value = try container.decode(T.self) - assert(container.isAtEnd) - } - static func ==(_ lhs: TopLevelWrapper, _ rhs: TopLevelWrapper) -> Bool { return lhs.value == rhs.value } @@ -550,6 +613,7 @@ PropertyListEncoderTests.test("testEncodingTopLevelStructuredClass") { TestPrope PropertyListEncoderTests.test("testEncodingTopLevelStructuredSingleStruct") { TestPropertyListEncoder().testEncodingTopLevelStructuredSingleStruct() } PropertyListEncoderTests.test("testEncodingTopLevelStructuredSingleClass") { TestPropertyListEncoder().testEncodingTopLevelStructuredSingleClass() } PropertyListEncoderTests.test("testEncodingTopLevelDeepStructuredType") { TestPropertyListEncoder().testEncodingTopLevelDeepStructuredType() } +PropertyListEncoderTests.test("testEncodingClassWhichSharesEncoderWithSuper") { TestPropertyListEncoder().testEncodingClassWhichSharesEncoderWithSuper() } PropertyListEncoderTests.test("testNestedContainerCodingPaths") { TestPropertyListEncoder().testNestedContainerCodingPaths() } PropertyListEncoderTests.test("testSuperEncoderCodingPaths") { TestPropertyListEncoder().testSuperEncoderCodingPaths() } runAllTests() diff --git a/test/stmt/nonexhaustive_switch_stmt_editor.swift b/test/stmt/nonexhaustive_switch_stmt_editor.swift new file mode 100644 index 00000000000..ee5d8624f43 --- /dev/null +++ b/test/stmt/nonexhaustive_switch_stmt_editor.swift @@ -0,0 +1,29 @@ +// RUN: %target-typecheck-verify-swift -diagnostics-editor-mode + +typealias TimeInterval = Double + +let NSEC_PER_USEC : UInt64 = 1000 +let NSEC_PER_SEC : UInt64 = 1000000000 + +public enum TemporalProxy { + case seconds(Int) + case milliseconds(Int) + case microseconds(Int) + case nanoseconds(Int) + @_downgrade_exhaustivity_check + case never +} + +func unproxify(t : TemporalProxy) -> TimeInterval { + switch t { // expected-warning {{switch must be exhaustive}} + // expected-note@-1 {{do you want to add missing cases?}} + case let .seconds(s): + return TimeInterval(s) + case let .milliseconds(ms): + return TimeInterval(TimeInterval(ms) / 1000.0) + case let .microseconds(us): + return TimeInterval( UInt64(us) * NSEC_PER_USEC ) / TimeInterval(NSEC_PER_SEC) + case let .nanoseconds(ns): + return TimeInterval(ns) / TimeInterval(NSEC_PER_SEC) + } +} diff --git a/test/swift_test.py b/test/swift_test.py index e0dad38875f..9f0f7a37ff8 100644 --- a/test/swift_test.py +++ b/test/swift_test.py @@ -31,6 +31,20 @@ class SwiftTest(lit.formats.ShTest, object): self.skipped_tests = set() def before_test(self, test, litConfig): + _, tmp_base = lit.TestRunner.getTempPaths(test) + + # Apparently despite the docs, tmpDir is not actually unique for each test, but + # tmpBase is. Remove it here and add a tmpBase substitution in before_test. + # Speculative fix for rdar://32928464. + try: + percentT_index = [x[0] for x in test.config.substitutions].index('%T') + except ValueError: pass + else: + test.config.substitutions.pop(percentT_index) + + test.config.substitutions.append( + ('%T', '$(mkdir -p %r && echo %r)' % (tmp_base, tmp_base))) + if self.coverage_mode: # FIXME: The compiler crashers run so fast they fill up the # merger's queue (and therefore the build bot's disk) @@ -39,7 +53,6 @@ class SwiftTest(lit.formats.ShTest, object): self.skipped_tests.add(test.getSourcePath()) return - _, tmp_base = lit.TestRunner.getTempPaths(test) if self.coverage_mode == "NOT_MERGED": profdir = tmp_base + '.profdir' if not os.path.exists(profdir): diff --git a/tools/SourceKit/include/SourceKit/Core/Context.h b/tools/SourceKit/include/SourceKit/Core/Context.h index 34c62d7edf5..9ca25674f56 100644 --- a/tools/SourceKit/include/SourceKit/Core/Context.h +++ b/tools/SourceKit/include/SourceKit/Core/Context.h @@ -35,7 +35,8 @@ class Context { public: Context(StringRef RuntimeLibPath, llvm::function_ref< - std::unique_ptr(Context &)> LangSupportFactoryFn); + std::unique_ptr(Context &)> LangSupportFactoryFn, + bool shouldDispatchNotificationsOnMain = true); ~Context(); StringRef getRuntimeLibPath() const { return RuntimeLibPath; } diff --git a/tools/SourceKit/include/SourceKit/Core/LangSupport.h b/tools/SourceKit/include/SourceKit/Core/LangSupport.h index 9514a114b9a..a02d1c6db87 100644 --- a/tools/SourceKit/include/SourceKit/Core/LangSupport.h +++ b/tools/SourceKit/include/SourceKit/Core/LangSupport.h @@ -153,6 +153,7 @@ struct FilterRule { Literal, CustomCompletion, Identifier, + Description, }; Kind kind; bool hide; diff --git a/tools/SourceKit/include/SourceKit/Core/NotificationCenter.h b/tools/SourceKit/include/SourceKit/Core/NotificationCenter.h index 30e9c629bd8..afb295e3d41 100644 --- a/tools/SourceKit/include/SourceKit/Core/NotificationCenter.h +++ b/tools/SourceKit/include/SourceKit/Core/NotificationCenter.h @@ -14,6 +14,7 @@ #define LLVM_SOURCEKIT_CORE_NOTIFICATIONCENTER_H #include "SourceKit/Core/LLVM.h" +#include "llvm/Support/Mutex.h" #include #include @@ -23,9 +24,14 @@ typedef std::function DocumentUpdateNotificationReceiver; class NotificationCenter { + bool DispatchToMain; std::vector DocUpdReceivers; + mutable llvm::sys::Mutex Mtx; public: + explicit NotificationCenter(bool dispatchToMain); + ~NotificationCenter(); + void addDocumentUpdateNotificationReceiver( DocumentUpdateNotificationReceiver Receiver); diff --git a/tools/SourceKit/include/SourceKit/Core/ProtocolUIDs.def b/tools/SourceKit/include/SourceKit/Core/ProtocolUIDs.def new file mode 100644 index 00000000000..8fb92f0c425 --- /dev/null +++ b/tools/SourceKit/include/SourceKit/Core/ProtocolUIDs.def @@ -0,0 +1,294 @@ +#ifndef KEY +#define KEY(NAME, CONTENT) +#endif + +#ifndef REQUEST +#define REQUEST(NAME, CONTENT) +#endif + +#ifndef KIND +#define KIND(NAME, CONTENT) +#endif + +KEY(VersionMajor, "key.version_major") +KEY(VersionMinor, "key.version_minor") +KEY(Results, "key.results") +KEY(Request, "key.request") +KEY(Notification, "key.notification") +KEY(Kind, "key.kind") +KEY(Accessibility, "key.accessibility") +KEY(SetterAccessibility, "key.setter_accessibility") +KEY(Keyword, "key.keyword") +KEY(Name, "key.name") +KEY(USR, "key.usr") +KEY(OriginalUSR, "key.original_usr") +KEY(DefaultImplementationOf, "key.default_implementation_of") +KEY(InterestedUSR, "key.interested_usr") +KEY(GenericParams, "key.generic_params") +KEY(GenericRequirements, "key.generic_requirements") +KEY(DocFullAsXML, "key.doc.full_as_xml") +KEY(Line, "key.line") +KEY(Column, "key.column") +KEY(ReceiverUSR, "key.receiver_usr") +KEY(IsDynamic, "key.is_dynamic") +KEY(FilePath, "key.filepath") +KEY(ModuleInterfaceName, "key.module_interface_name") +KEY(Hash, "key.hash") +KEY(CompilerArgs, "key.compilerargs") +KEY(Severity, "key.severity") +KEY(Offset, "key.offset") +KEY(Length, "key.length") +KEY(SourceFile, "key.sourcefile") +KEY(SourceText, "key.sourcetext") +KEY(EnableSyntaxMap, "key.enablesyntaxmap") +KEY(EnableStructure, "key.enablesubstructure") +KEY(Description, "key.description") +KEY(TypeName, "key.typename") +KEY(RuntimeName, "key.runtime_name") +KEY(SelectorName, "key.selector_name") +KEY(AnnotatedDecl, "key.annotated_decl") +KEY(FullyAnnotatedDecl, "key.fully_annotated_decl") +KEY(DocBrief, "key.doc.brief") +KEY(Context, "key.context") +KEY(ModuleImportDepth, "key.moduleimportdepth") +KEY(NumBytesToErase, "key.num_bytes_to_erase") +KEY(NotRecommended, "key.not_recommended") +KEY(Annotations, "key.annotations") +KEY(DiagnosticStage, "key.diagnostic_stage") +KEY(SyntaxMap, "key.syntaxmap") +KEY(IsSystem, "key.is_system") +KEY(Related, "key.related") +KEY(Inherits, "key.inherits") +KEY(Conforms, "key.conforms") +KEY(Extends, "key.extends") +KEY(Dependencies, "key.dependencies") +KEY(Entities, "key.entities") +KEY(NameOffset, "key.nameoffset") +KEY(NameLength, "key.namelength") +KEY(BodyOffset, "key.bodyoffset") +KEY(BodyLength, "key.bodylength") +KEY(ThrowOffset, "key.throwoffset") +KEY(ThrowLength, "key.throwlength") +KEY(IsLocal, "key.is_local") +KEY(InheritedTypes, "key.inheritedtypes") +KEY(Attributes, "key.attributes") +KEY(Attribute, "key.attribute") +KEY(Elements, "key.elements") +KEY(SubStructure, "key.substructure") +KEY(Ranges, "key.ranges") +KEY(Fixits, "key.fixits") +KEY(Diagnostics, "key.diagnostics") +KEY(FormatOptions, "key.editor.format.options") +KEY(CodeCompleteOptions, "key.codecomplete.options") +KEY(FilterRules, "key.codecomplete.filterrules") +KEY(NextRequestStart, "key.nextrequeststart") +KEY(Popular, "key.popular") +KEY(Unpopular, "key.unpopular") +KEY(Hide, "key.hide") +KEY(Platform, "key.platform") +KEY(IsDeprecated, "key.is_deprecated") +KEY(IsUnavailable, "key.is_unavailable") +KEY(IsOptional, "key.is_optional") +KEY(Message, "key.message") +KEY(Introduced, "key.introduced") +KEY(Deprecated, "key.deprecated") +KEY(Obsoleted, "key.obsoleted") +KEY(RemoveCache, "key.removecache") +KEY(TypeInterface, "key.typeinterface") +KEY(TypeUsr, "key.typeusr") +KEY(ContainerTypeUsr, "key.containertypeusr") +KEY(ModuleGroups, "key.modulegroups") +KEY(BaseName, "key.basename") +KEY(ArgNames, "key.argnames") +KEY(SelectorPieces, "key.selectorpieces") +KEY(NameKind, "key.namekind") +KEY(LocalizationKey, "key.localization_key") +KEY(IsZeroArgSelector, "key.is_zero_arg_selector") +KEY(SwiftVersion, "key.swift_version") + +KEY(EnableDiagnostics, "key.enablediagnostics") +KEY(GroupName, "key.groupname") +KEY(ActionName, "key.actionname") +KEY(SynthesizedExtension, "key.synthesizedextensions") + +KEY(Names, "key.names") +KEY(UIDs, "key.uids") +KEY(SyntacticOnly, "key.syntactic_only") +KEY(Actionable, "key.actionable") +KEY(ParentLoc, "key.parent_loc") +KEY(IsTestCandidate, "key.is_test_candidate") +KEY(Overrides, "key.overrides") +KEY(AssociatedUSRs, "key.associated_usrs") +KEY(ModuleName, "key.modulename") +KEY(RelatedDecls, "key.related_decls") +KEY(Simplified, "key.simplified") +KEY(RangeContent, "key.rangecontent") +KEY(CancelOnSubsequentRequest, "key.cancel_on_subsequent_request") + +REQUEST(ProtocolVersion, "source.request.protocol_version") +REQUEST(CrashWithExit, "source.request.crash_exit") +REQUEST(Demangle, "source.request.demangle") +REQUEST(MangleSimpleClass, "source.request.mangle_simple_class") +REQUEST(Index, "source.request.indexsource") +REQUEST(DocInfo, "source.request.docinfo") +REQUEST(CodeComplete, "source.request.codecomplete") +REQUEST(CodeCompleteOpen, "source.request.codecomplete.open") +REQUEST(CodeCompleteClose, "source.request.codecomplete.close") +REQUEST(CodeCompleteUpdate, "source.request.codecomplete.update") +REQUEST(CodeCompleteCacheOnDisk, "source.request.codecomplete.cache.ondisk") +REQUEST(CodeCompleteSetPopularAPI, "source.request.codecomplete.setpopularapi") +REQUEST(CodeCompleteSetCustom, "source.request.codecomplete.setcustom") +REQUEST(CursorInfo, "source.request.cursorinfo") +REQUEST(RangeInfo, "source.request.rangeinfo") +REQUEST(RelatedIdents, "source.request.relatedidents") +REQUEST(EditorOpen, "source.request.editor.open") +REQUEST(EditorOpenInterface, "source.request.editor.open.interface") +REQUEST(EditorOpenHeaderInterface, "source.request.editor.open.interface.header") +REQUEST(EditorOpenSwiftSourceInterface, "source.request.editor.open.interface.swiftsource") +REQUEST(EditorOpenSwiftTypeInterface, "source.request.editor.open.interface.swifttype") +REQUEST(EditorExtractTextFromComment, "source.request.editor.extract.comment") +REQUEST(EditorClose, "source.request.editor.close") +REQUEST(EditorReplaceText, "source.request.editor.replacetext") +REQUEST(EditorFormatText, "source.request.editor.formattext") +REQUEST(EditorExpandPlaceholder, "source.request.editor.expand_placeholder") +REQUEST(EditorFindUSR, "source.request.editor.find_usr") +REQUEST(EditorFindInterfaceDoc, "source.request.editor.find_interface_doc") +REQUEST(BuildSettingsRegister, "source.request.buildsettings.register") +REQUEST(ModuleGroups, "source.request.module.groups") +REQUEST(NameTranslation, "source.request.name.translation") +REQUEST(MarkupToXML, "source.request.convert.markup.xml") + +KIND(DeclFunctionFree, "source.lang.swift.decl.function.free") +KIND(RefFunctionFree, "source.lang.swift.ref.function.free") +KIND(DeclMethodInstance, "source.lang.swift.decl.function.method.instance") +KIND(RefMethodInstance, "source.lang.swift.ref.function.method.instance") +KIND(DeclMethodStatic, "source.lang.swift.decl.function.method.static") +KIND(RefMethodStatic, "source.lang.swift.ref.function.method.static") +KIND(DeclMethodClass, "source.lang.swift.decl.function.method.class") +KIND(RefMethodClass, "source.lang.swift.ref.function.method.class") +KIND(DeclAccessorGetter, "source.lang.swift.decl.function.accessor.getter") +KIND(RefAccessorGetter, "source.lang.swift.ref.function.accessor.getter") +KIND(DeclAccessorSetter, "source.lang.swift.decl.function.accessor.setter") +KIND(RefAccessorSetter, "source.lang.swift.ref.function.accessor.setter") +KIND(DeclAccessorWillSet, "source.lang.swift.decl.function.accessor.willset") +KIND(RefAccessorWillSet, "source.lang.swift.ref.function.accessor.willset") +KIND(DeclAccessorDidSet, "source.lang.swift.decl.function.accessor.didset") +KIND(RefAccessorDidSet, "source.lang.swift.ref.function.accessor.didset") +KIND(DeclAccessorAddress, "source.lang.swift.decl.function.accessor.address") +KIND(RefAccessorAddress, "source.lang.swift.ref.function.accessor.address") +KIND(DeclAccessorMutableAddress, "source.lang.swift.decl.function.accessor.mutableaddress") +KIND(RefAccessorMutableAddress, "source.lang.swift.ref.function.accessor.mutableaddress") +KIND(DeclConstructor, "source.lang.swift.decl.function.constructor") +KIND(RefConstructor, "source.lang.swift.ref.function.constructor") +KIND(DeclDestructor, "source.lang.swift.decl.function.destructor") +KIND(RefDestructor, "source.lang.swift.ref.function.destructor") +KIND(DeclFunctionPrefixOperator, "source.lang.swift.decl.function.operator.prefix") +KIND(DeclFunctionPostfixOperator, "source.lang.swift.decl.function.operator.postfix") +KIND(DeclFunctionInfixOperator, "source.lang.swift.decl.function.operator.infix") +KIND(RefFunctionPrefixOperator, "source.lang.swift.ref.function.operator.prefix") +KIND(RefFunctionPostfixOperator, "source.lang.swift.ref.function.operator.postfix") +KIND(RefFunctionInfixOperator, "source.lang.swift.ref.function.operator.infix") +KIND(DeclPrecedenceGroup, "source.lang.swift.decl.precedencegroup") +KIND(RefPrecedenceGroup, "source.lang.swift.ref.precedencegroup") +KIND(DeclSubscript, "source.lang.swift.decl.function.subscript") +KIND(RefSubscript, "source.lang.swift.ref.function.subscript") +KIND(DeclVarGlobal, "source.lang.swift.decl.var.global") +KIND(RefVarGlobal, "source.lang.swift.ref.var.global") +KIND(DeclVarInstance, "source.lang.swift.decl.var.instance") +KIND(RefVarInstance, "source.lang.swift.ref.var.instance") +KIND(DeclVarStatic, "source.lang.swift.decl.var.static") +KIND(RefVarStatic, "source.lang.swift.ref.var.static") +KIND(DeclVarClass, "source.lang.swift.decl.var.class") +KIND(RefVarClass, "source.lang.swift.ref.var.class") +KIND(DeclVarLocal, "source.lang.swift.decl.var.local") +KIND(RefVarLocal, "source.lang.swift.ref.var.local") +KIND(DeclVarParam, "source.lang.swift.decl.var.parameter") +KIND(DeclModule, "source.lang.swift.decl.module") +KIND(DeclClass, "source.lang.swift.decl.class") +KIND(RefClass, "source.lang.swift.ref.class") +KIND(DeclStruct, "source.lang.swift.decl.struct") +KIND(RefStruct, "source.lang.swift.ref.struct") +KIND(DeclEnum, "source.lang.swift.decl.enum") +KIND(RefEnum, "source.lang.swift.ref.enum") +KIND(DeclEnumCase, "source.lang.swift.decl.enumcase") +KIND(DeclEnumElement, "source.lang.swift.decl.enumelement") +KIND(RefEnumElement, "source.lang.swift.ref.enumelement") +KIND(DeclProtocol, "source.lang.swift.decl.protocol") +KIND(RefProtocol, "source.lang.swift.ref.protocol") +KIND(DeclExtension, "source.lang.swift.decl.extension") +KIND(DeclExtensionStruct, "source.lang.swift.decl.extension.struct") +KIND(DeclExtensionClass, "source.lang.swift.decl.extension.class") +KIND(DeclExtensionEnum, "source.lang.swift.decl.extension.enum") +KIND(DeclExtensionProtocol, "source.lang.swift.decl.extension.protocol") +KIND(DeclAssociatedType, "source.lang.swift.decl.associatedtype") +KIND(RefAssociatedType, "source.lang.swift.ref.associatedtype") +KIND(DeclTypeAlias, "source.lang.swift.decl.typealias") +KIND(RefTypeAlias, "source.lang.swift.ref.typealias") +KIND(DeclGenericTypeParam, "source.lang.swift.decl.generic_type_param") +KIND(RefGenericTypeParam, "source.lang.swift.ref.generic_type_param") +KIND(RefModule, "source.lang.swift.ref.module") +KIND(StmtForEach, "source.lang.swift.stmt.foreach") +KIND(StmtFor, "source.lang.swift.stmt.for") +KIND(StmtWhile, "source.lang.swift.stmt.while") +KIND(StmtRepeatWhile, "source.lang.swift.stmt.repeatwhile") +KIND(StmtIf, "source.lang.swift.stmt.if") +KIND(StmtGuard, "source.lang.swift.stmt.guard") +KIND(StmtSwitch, "source.lang.swift.stmt.switch") +KIND(StmtCase, "source.lang.swift.stmt.case") +KIND(StmtBrace, "source.lang.swift.stmt.brace") +KIND(ExprCall, "source.lang.swift.expr.call") +KIND(ExprArg, "source.lang.swift.expr.argument") +KIND(ExprArray, "source.lang.swift.expr.array") +KIND(ExprDictionary, "source.lang.swift.expr.dictionary") +KIND(ExprObjectLiteral, "source.lang.swift.expr.object_literal") +KIND(StructureElemId, "source.lang.swift.structure.elem.id") +KIND(StructureElemExpr, "source.lang.swift.structure.elem.expr") +KIND(StructureElemInitExpr, "source.lang.swift.structure.elem.init_expr") +KIND(StructureElemCondExpr, "source.lang.swift.structure.elem.condition_expr") +KIND(StructureElemPattern, "source.lang.swift.structure.elem.pattern") +KIND(StructureElemTypeRef, "source.lang.swift.structure.elem.typeref") +KIND(RangeSingleStatement, "source.lang.swift.range.singlestatement") +KIND(RangeSingleExpression, "source.lang.swift.range.singleexpression") +KIND(RangeSingleDeclaration, "source.lang.swift.range.singledeclaration") +KIND(RangeMultiStatement, "source.lang.swift.range.multistatement") +KIND(RangeInvalid, "source.lang.swift.range.invalid") +KIND(NameObjc, "source.lang.name.kind.objc") +KIND(NameSwift, "source.lang.name.kind.swift") +KIND(Keyword, "source.lang.swift.syntaxtype.keyword") +KIND(Identifier, "source.lang.swift.syntaxtype.identifier") +KIND(TypeIdentifier, "source.lang.swift.syntaxtype.typeidentifier") +KIND(BuildConfigKeyword, "source.lang.swift.syntaxtype.buildconfig.keyword") +KIND(BuildConfigId, "source.lang.swift.syntaxtype.buildconfig.id") +KIND(AttributeId, "source.lang.swift.syntaxtype.attribute.id") +KIND(AttributeBuiltin, "source.lang.swift.syntaxtype.attribute.builtin") +KIND(Number, "source.lang.swift.syntaxtype.number") +KIND(String, "source.lang.swift.syntaxtype.string") +KIND(StringInterpolation, "source.lang.swift.syntaxtype.string_interpolation_anchor") +KIND(Comment, "source.lang.swift.syntaxtype.comment") +KIND(DocComment, "source.lang.swift.syntaxtype.doccomment") +KIND(DocCommentField, "source.lang.swift.syntaxtype.doccomment.field") +KIND(CommentMarker, "source.lang.swift.syntaxtype.comment.mark") +KIND(CommentURL, "source.lang.swift.syntaxtype.comment.url") +KIND(Placeholder, "source.lang.swift.syntaxtype.placeholder") +KIND(ObjectLiteral, "source.lang.swift.syntaxtype.objectliteral") + +KIND(Expr, "source.lang.swift.expr") +KIND(Stmt, "source.lang.swift.stmt") +KIND(Type, "source.lang.swift.type") + +KIND(DiagNote, "source.diagnostic.severity.note") +KIND(DiagWarning, "source.diagnostic.severity.warning") +KIND(DiagError, "source.diagnostic.severity.error") + +KIND(CodeCompletionKeyword, "source.codecompletion.keyword") +KIND(CodeCompletionEverything, "source.codecompletion.everything") +KIND(CodeCompletionModule, "source.codecompletion.module") +KIND(CodeCompletionCodeCompleteKeyword, "source.codecompletion.keyword") +KIND(CodeCompletionLiteral, "source.codecompletion.literal") +KIND(CodeCompletionCustom, "source.codecompletion.custom") +KIND(CodeCompletionIdentifier, "source.codecompletion.identifier") +KIND(CodeCompletionDescription, "source.codecompletion.description") + +#undef KIND +#undef REQUEST +#undef KEY diff --git a/tools/SourceKit/lib/Core/Context.cpp b/tools/SourceKit/lib/Core/Context.cpp index 17d3138f7e5..066b5bbfdad 100644 --- a/tools/SourceKit/lib/Core/Context.cpp +++ b/tools/SourceKit/lib/Core/Context.cpp @@ -18,8 +18,9 @@ using namespace SourceKit; SourceKit::Context::Context(StringRef RuntimeLibPath, llvm::function_ref(Context &)> - LangSupportFactoryFn) : RuntimeLibPath(RuntimeLibPath), - NotificationCtr(new NotificationCenter()) { + LangSupportFactoryFn, + bool shouldDispatchNotificationsOnMain) : RuntimeLibPath(RuntimeLibPath), + NotificationCtr(new NotificationCenter(shouldDispatchNotificationsOnMain)) { // Should be called last after everything is initialized. SwiftLang = LangSupportFactoryFn(*this); } diff --git a/tools/SourceKit/lib/Core/NotificationCenter.cpp b/tools/SourceKit/lib/Core/NotificationCenter.cpp index fcc39e4a220..e7e2e163a7f 100644 --- a/tools/SourceKit/lib/Core/NotificationCenter.cpp +++ b/tools/SourceKit/lib/Core/NotificationCenter.cpp @@ -15,20 +15,33 @@ using namespace SourceKit; +NotificationCenter::NotificationCenter(bool dispatchToMain) + : DispatchToMain(dispatchToMain) { +} +NotificationCenter::~NotificationCenter() {} + void NotificationCenter::addDocumentUpdateNotificationReceiver( DocumentUpdateNotificationReceiver Receiver) { - WorkQueue::dispatchOnMain([this, Receiver]{ - DocUpdReceivers.push_back(Receiver); - }); + llvm::sys::ScopedLock L(Mtx); + DocUpdReceivers.push_back(Receiver); } void NotificationCenter::postDocumentUpdateNotification( StringRef DocumentName) const { - - std::string DocName = DocumentName; - WorkQueue::dispatchOnMain([this, DocName]{ - for (auto &Fn : DocUpdReceivers) - Fn(DocName); - }); + + std::vector recvs; + { + llvm::sys::ScopedLock L(Mtx); + recvs = DocUpdReceivers; + } + std::string docName = DocumentName; + auto sendNote = [recvs, docName]{ + for (auto &Fn : recvs) + Fn(docName); + }; + if (DispatchToMain) + WorkQueue::dispatchOnMain(sendNote); + else + sendNote(); } diff --git a/tools/SourceKit/lib/SwiftLang/CodeCompletion.h b/tools/SourceKit/lib/SwiftLang/CodeCompletion.h index ae0de578f2c..681340f609a 100644 --- a/tools/SourceKit/lib/SwiftLang/CodeCompletion.h +++ b/tools/SourceKit/lib/SwiftLang/CodeCompletion.h @@ -231,13 +231,13 @@ struct FilterRules { // FIXME: hide individual custom completions llvm::StringMap hideModule; - llvm::StringMap hideByName; + llvm::StringMap hideByFilterName; + llvm::StringMap hideByDescription; bool hideCompletion(Completion *completion) const; - bool hideCompletion(SwiftResult *completion, - StringRef name, - void *customKind = nullptr) const; - bool hideName(StringRef name) const; + bool hideCompletion(SwiftResult *completion, StringRef name, + StringRef description, void *customKind = nullptr) const; + bool hideFilterName(StringRef name) const; }; } // end namespace CodeCompletion diff --git a/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp b/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp index c54b3f4931f..68fcae639ff 100644 --- a/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp +++ b/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp @@ -447,22 +447,32 @@ static bool isHighPriorityKeyword(CodeCompletionKeywordKind kind) { } } -bool FilterRules::hideName(StringRef name) const { - auto I = hideByName.find(name); - if (I != hideByName.end()) - return I->getValue(); +bool FilterRules::hideFilterName(StringRef name) const { + auto I = hideByFilterName.find(name); + if (I != hideByFilterName.end()) + return I->getValue(); return hideAll; } bool FilterRules::hideCompletion(Completion *completion) const { - return hideCompletion(completion, completion->getName(), completion->getCustomKind()); + return hideCompletion(completion, completion->getName(), + completion->getDescription(), + completion->getCustomKind()); } -bool FilterRules::hideCompletion(SwiftResult *completion, StringRef name, void *customKind) const { +bool FilterRules::hideCompletion(SwiftResult *completion, StringRef filterName, + StringRef description, + void *customKind) const { - if (!name.empty()) { - auto I = hideByName.find(name); - if (I != hideByName.end()) + if (!description.empty()) { + auto I = hideByDescription.find(description); + if (I != hideByDescription.end()) + return I->getValue(); + } + + if (!filterName.empty()) { + auto I = hideByFilterName.find(filterName); + if (I != hideByFilterName.end()) return I->getValue(); } diff --git a/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp b/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp index 7b3a7331e90..23a8392d0a9 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp @@ -887,7 +887,12 @@ static void translateFilterRules(ArrayRef rawFilterRules, // Note: name is null-terminated. if (canonicalizeFilterName(name.data(), canonName)) continue; - filterRules.hideByName[canonName] = rule.hide; + filterRules.hideByFilterName[canonName] = rule.hide; + } + break; + case FilterRule::Description: + for (auto name : rule.names) { + filterRules.hideByDescription[name] = rule.hide; } break; case FilterRule::Module: @@ -955,13 +960,19 @@ filterInnerResults(ArrayRef results, bool includeInner, if (!includeInnerOperators && result->isOperator()) continue; - llvm::SmallString<64> name; + llvm::SmallString<64> filterName; { - llvm::raw_svector_ostream OSS(name); + llvm::raw_svector_ostream OSS(filterName); CodeCompletion::CompletionBuilder::getFilterName( result->getCompletionString(), OSS); } - if (rules.hideCompletion(result, name)) + llvm::SmallString<64> description; + { + llvm::raw_svector_ostream OSS(description); + CodeCompletion::CompletionBuilder::getDescription( + result, OSS, /*leadingPunctuation=*/false); + } + if (rules.hideCompletion(result, filterName, description)) continue; bool inner = checkInnerResult(result, hasDot, hasQDot, hasInit); @@ -1040,11 +1051,11 @@ static void transformAndForwardResults( options.addInnerOperators, hasDot, hasQDot, hasInit, rules); if (options.addInnerOperators) { - if (hasInit && !rules.hideName("(")) + if (hasInit && !rules.hideFilterName("(")) innerResults.insert(innerResults.begin(), buildParen()); - if (hasDot && !rules.hideName(".")) + if (hasDot && !rules.hideFilterName(".")) innerResults.insert(innerResults.begin(), buildDot()); - if (hasQDot && !rules.hideName("?.")) + if (hasQDot && !rules.hideFilterName("?.")) innerResults.insert(innerResults.begin(), buildQDot()); } @@ -1095,11 +1106,11 @@ static void transformAndForwardResults( } if (options.addInnerOperators) { - if (hasInit && !rules.hideName("(")) + if (hasInit && !rules.hideFilterName("(")) innerResults.insert(innerResults.begin(), buildParen()); - if (hasDot && !rules.hideName(".")) + if (hasDot && !rules.hideFilterName(".")) innerResults.insert(innerResults.begin(), buildDot()); - if (hasQDot && !rules.hideName("?.")) + if (hasQDot && !rules.hideFilterName("?.")) innerResults.insert(innerResults.begin(), buildQDot()); } diff --git a/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp b/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp index abc18de922f..9be21de1910 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp @@ -435,7 +435,7 @@ public: void readSemanticInfo(ImmutableTextSnapshotRef NewSnapshot, std::vector &Tokens, - std::vector &Diags, + Optional> &Diags, ArrayRef ParserDiags); void processLatestSnapshotAsync(EditableTextBufferRef EditableBuffer); @@ -453,7 +453,7 @@ private: std::vector takeSemanticTokens( ImmutableTextSnapshotRef NewSnapshot); - std::vector getSemanticDiagnostics( + Optional> getSemanticDiagnostics( ImmutableTextSnapshotRef NewSnapshot, ArrayRef ParserDiags); }; @@ -545,7 +545,7 @@ uint64_t SwiftDocumentSemanticInfo::getASTGeneration() const { void SwiftDocumentSemanticInfo::readSemanticInfo( ImmutableTextSnapshotRef NewSnapshot, std::vector &Tokens, - std::vector &Diags, + Optional> &Diags, ArrayRef ParserDiags) { llvm::sys::ScopedLock L(Mtx); @@ -600,155 +600,73 @@ SwiftDocumentSemanticInfo::takeSemanticTokens( return std::move(SemaToks); } -static bool -adjustDiagnosticRanges(SmallVectorImpl> &Ranges, - unsigned ByteOffset, unsigned RemoveLen, int Delta) { - for (auto &Range : Ranges) { - unsigned RangeBegin = Range.first; - unsigned RangeEnd = Range.first + Range.second; - unsigned RemoveEnd = ByteOffset + RemoveLen; - // If it intersects with the remove range, ignore the whole diagnostic. - if (!(RangeEnd < ByteOffset || RangeBegin > RemoveEnd)) - return true; // Ignore. - if (RangeBegin > RemoveEnd) - Range.first += Delta; - } - return false; -} - -static bool -adjustDiagnosticFixits(SmallVectorImpl &Fixits, - unsigned ByteOffset, unsigned RemoveLen, int Delta) { - for (auto &Fixit : Fixits) { - unsigned FixitBegin = Fixit.Offset; - unsigned FixitEnd = Fixit.Offset + Fixit.Length; - unsigned RemoveEnd = ByteOffset + RemoveLen; - // If it intersects with the remove range, ignore the whole diagnostic. - if (!(FixitEnd < ByteOffset || FixitBegin > RemoveEnd)) - return true; // Ignore. - if (FixitBegin > RemoveEnd) - Fixit.Offset += Delta; - } - return false; -} - -static bool -adjustDiagnosticBase(DiagnosticEntryInfoBase &Diag, - unsigned ByteOffset, unsigned RemoveLen, int Delta) { - if (Diag.Offset >= ByteOffset && Diag.Offset < ByteOffset+RemoveLen) - return true; // Ignore. - bool Ignore = adjustDiagnosticRanges(Diag.Ranges, ByteOffset, RemoveLen, Delta); - if (Ignore) - return true; - Ignore = adjustDiagnosticFixits(Diag.Fixits, ByteOffset, RemoveLen, Delta); - if (Ignore) - return true; - if (Diag.Offset > ByteOffset) - Diag.Offset += Delta; - return false; -} - -static bool -adjustDiagnostic(DiagnosticEntryInfo &Diag, StringRef Filename, - unsigned ByteOffset, unsigned RemoveLen, int Delta) { - for (auto &Note : Diag.Notes) { - if (Filename != Note.Filename) - continue; - bool Ignore = adjustDiagnosticBase(Note, ByteOffset, RemoveLen, Delta); - if (Ignore) - return true; - } - return adjustDiagnosticBase(Diag, ByteOffset, RemoveLen, Delta); -} - -static std::vector -adjustDiagnostics(std::vector Diags, StringRef Filename, - unsigned ByteOffset, unsigned RemoveLen, int Delta) { - std::vector NewDiags; - NewDiags.reserve(Diags.size()); - - for (auto &Diag : Diags) { - bool Ignore = adjustDiagnostic(Diag, Filename, ByteOffset, RemoveLen, Delta); - if (!Ignore) { - NewDiags.push_back(std::move(Diag)); - } - } - - return NewDiags; -} - -std::vector +Optional> SwiftDocumentSemanticInfo::getSemanticDiagnostics( ImmutableTextSnapshotRef NewSnapshot, ArrayRef ParserDiags) { - llvm::sys::ScopedLock L(Mtx); + std::vector curSemaDiags; + { + llvm::sys::ScopedLock L(Mtx); - if (SemaDiags.empty()) - return SemaDiags; - - assert(DiagSnapshot && "If we have diagnostics, we must have snapshot!"); - - if (!DiagSnapshot->precedesOrSame(NewSnapshot)) { - // It may happen that other thread has already updated the diagnostics to - // the version *after* NewSnapshot. This can happen in at least two cases: - // (a) two or more editor.open or editor.replacetext queries are being - // processed concurrently (not valid, but possible call pattern) - // (b) while editor.replacetext processing is running, a concurrent - // thread executes getBuffer()/getBufferForSnapshot() on the same - // Snapshot/EditableBuffer (thus creating a new ImmutableTextBuffer) - // and updates DiagSnapshot/SemaDiags - assert(NewSnapshot->precedesOrSame(DiagSnapshot)); - - // Since we cannot "adjust back" diagnostics, we just return an empty set. - // FIXME: add handling of the case#b above - return {}; - } - - SmallVector ParserDiagLines; - for (auto Diag : ParserDiags) - ParserDiagLines.push_back(Diag.Line); - std::sort(ParserDiagLines.begin(), ParserDiagLines.end()); - - auto hasParserDiagAtLine = [&](unsigned Line) { - return std::binary_search(ParserDiagLines.begin(), ParserDiagLines.end(), - Line); - }; - - // Adjust the position of the diagnostics. - DiagSnapshot->foreachReplaceUntil(NewSnapshot, - [&](ReplaceImmutableTextUpdateRef Upd) -> bool { - if (SemaDiags.empty()) - return false; - - unsigned ByteOffset = Upd->getByteOffset(); - unsigned RemoveLen = Upd->getLength(); - unsigned InsertLen = Upd->getText().size(); - int Delta = InsertLen - RemoveLen; - SemaDiags = adjustDiagnostics(std::move(SemaDiags), Filename, - ByteOffset, RemoveLen, Delta); - return true; - }); - - if (!SemaDiags.empty()) { - auto ImmBuf = NewSnapshot->getBuffer(); - for (auto &Diag : SemaDiags) { - std::tie(Diag.Line, Diag.Column) = ImmBuf->getLineAndColumn(Diag.Offset); + if (!DiagSnapshot || DiagSnapshot->getStamp() != NewSnapshot->getStamp()) { + // The semantic diagnostics are out-of-date, ignore them. + return llvm::None; } - // If there is a parser diagnostic in a line, ignore diagnostics in the same - // line that we got from the semantic pass. - // Note that the semantic pass also includes parser diagnostics so this - // avoids duplicates. - SemaDiags.erase(std::remove_if(SemaDiags.begin(), SemaDiags.end(), - [&](const DiagnosticEntryInfo &Diag) -> bool { - return hasParserDiagAtLine(Diag.Line); - }), - SemaDiags.end()); + curSemaDiags = SemaDiags; } - DiagSnapshot = NewSnapshot; - return SemaDiags; + // Diagnostics from the AST and diagnostics from the parser are based on the + // same source text snapshot. But diagnostics from the AST may have excluded + // the parser diagnostics due to a fatal error, e.g. if the source has a + // 'so such module' error, which will suppress other diagnostics. + // We don't want to turn off the suppression to avoid a flood of diagnostics + // when a module import fails, but we also don't want to lose the parser + // diagnostics in such a case, so merge the parser diagnostics with the sema + // ones. + + auto orderDiagnosticEntryInfos = [](const DiagnosticEntryInfo &LHS, + const DiagnosticEntryInfo &RHS) -> bool { + if (LHS.Filename != RHS.Filename) + return LHS.Filename < RHS.Filename; + if (LHS.Offset != RHS.Offset) + return LHS.Offset < RHS.Offset; + return LHS.Description < RHS.Description; + }; + + std::vector sortedParserDiags; + sortedParserDiags.reserve(ParserDiags.size()); + sortedParserDiags.insert(sortedParserDiags.end(), ParserDiags.begin(), + ParserDiags.end()); + std::stable_sort(sortedParserDiags.begin(), sortedParserDiags.end(), + orderDiagnosticEntryInfos); + + std::vector finalDiags; + finalDiags.reserve(sortedParserDiags.size()+curSemaDiags.size()); + + // Add sema diagnostics unless it is an existing parser diagnostic. + // Note that we want to merge and eliminate diagnostics from the 'sema' set + // that also show up in the 'parser' set, but we don't want to remove + // duplicate diagnostics from within the same set (e.g. duplicates existing in + // the 'sema' set). We want to report the diagnostics as the compiler reported + // them, even if there's some duplicate one. This is why we don't just do a + // simple append/sort/keep-uniques step. + for (const auto &curDE : curSemaDiags) { + bool existsAsParserDiag = std::binary_search(sortedParserDiags.begin(), + sortedParserDiags.end(), + curDE, orderDiagnosticEntryInfos); + if (!existsAsParserDiag) { + finalDiags.push_back(curDE); + } + } + + finalDiags.insert(finalDiags.end(), + sortedParserDiags.begin(), sortedParserDiags.end()); + std::stable_sort(finalDiags.begin(), finalDiags.end(), + orderDiagnosticEntryInfos); + + return finalDiags; } void SwiftDocumentSemanticInfo::updateSemanticInfo( @@ -1428,18 +1346,17 @@ private: if (auto *FTR = dyn_cast(T)) { FoundFunctionTypeRepr = true; if (auto *TTR = dyn_cast_or_null(FTR->getArgsTypeRepr())) { - for (unsigned i = 0, end = TTR->getNumElements(); i != end; ++i) { - auto *ArgTR = TTR->getElement(i); + for (auto &ArgElt : TTR->getElements()) { CharSourceRange NR; CharSourceRange TR; - auto name = TTR->getElementName(i); + auto name = ArgElt.Name; if (!name.empty()) { - NR = CharSourceRange(TTR->getElementNameLoc(i), + NR = CharSourceRange(ArgElt.NameLoc, name.getLength()); } SourceLoc SRE = Lexer::getLocForEndOfToken(SM, - ArgTR->getEndLoc()); - TR = CharSourceRange(SM, ArgTR->getStartLoc(), SRE); + ArgElt.Type->getEndLoc()); + TR = CharSourceRange(SM, ArgElt.Type->getStartLoc(), SRE); Info.Params.emplace_back(NR, TR); } } else if (FTR->getArgsTypeRepr()) { @@ -1787,10 +1704,7 @@ void SwiftEditorDocument::readSemanticInfo(ImmutableTextSnapshotRef Snapshot, } std::vector SemaToks; - std::vector SemaDiags; - - // FIXME: Parser diagnostics should be filtered out of the semantic ones, - // Then just merge the semantic ones with the current parse ones. + Optional> SemaDiags; Impl.SemanticInfo->readSemanticInfo(Snapshot, SemaToks, SemaDiags, Impl.ParserDiagnostics); @@ -1807,16 +1721,17 @@ void SwiftEditorDocument::readSemanticInfo(ImmutableTextSnapshotRef Snapshot, static UIdent SemaDiagStage("source.diagnostic.stage.swift.sema"); static UIdent ParseDiagStage("source.diagnostic.stage.swift.parse"); - if (!SemaDiags.empty() || !SemaToks.empty()) { + // If there's no value returned for diagnostics it means they are out-of-date + // (based on a different snapshot). + if (SemaDiags.hasValue()) { Consumer.setDiagnosticStage(SemaDiagStage); + for (auto &Diag : SemaDiags.getValue()) + Consumer.handleDiagnostic(Diag, SemaDiagStage); } else { Consumer.setDiagnosticStage(ParseDiagStage); + for (auto &Diag : Impl.ParserDiagnostics) + Consumer.handleDiagnostic(Diag, ParseDiagStage); } - - for (auto &Diag : Impl.ParserDiagnostics) - Consumer.handleDiagnostic(Diag, ParseDiagStage); - for (auto &Diag : SemaDiags) - Consumer.handleDiagnostic(Diag, SemaDiagStage); } void SwiftEditorDocument::removeCachedAST() { diff --git a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp index d2712daba4e..91624ca8643 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp @@ -52,126 +52,8 @@ using swift::index::SymbolInfo; using swift::index::SymbolRole; using swift::index::SymbolRoleSet; -static UIdent KindDeclFunctionFree("source.lang.swift.decl.function.free"); -static UIdent KindRefFunctionFree("source.lang.swift.ref.function.free"); -static UIdent KindDeclMethodInstance( - "source.lang.swift.decl.function.method.instance"); -static UIdent KindRefMethodInstance( - "source.lang.swift.ref.function.method.instance"); -static UIdent KindDeclMethodStatic( - "source.lang.swift.decl.function.method.static"); -static UIdent KindRefMethodStatic( - "source.lang.swift.ref.function.method.static"); -static UIdent KindDeclMethodClass( - "source.lang.swift.decl.function.method.class"); -static UIdent KindRefMethodClass( - "source.lang.swift.ref.function.method.class"); -static UIdent KindDeclAccessorGetter( - "source.lang.swift.decl.function.accessor.getter"); -static UIdent KindRefAccessorGetter( - "source.lang.swift.ref.function.accessor.getter"); -static UIdent KindDeclAccessorSetter( - "source.lang.swift.decl.function.accessor.setter"); -static UIdent KindRefAccessorSetter( - "source.lang.swift.ref.function.accessor.setter"); -static UIdent KindDeclAccessorWillSet( - "source.lang.swift.decl.function.accessor.willset"); -static UIdent KindRefAccessorWillSet( - "source.lang.swift.ref.function.accessor.willset"); -static UIdent KindDeclAccessorDidSet( - "source.lang.swift.decl.function.accessor.didset"); -static UIdent KindRefAccessorDidSet( - "source.lang.swift.ref.function.accessor.didset"); -static UIdent KindDeclAccessorAddress( - "source.lang.swift.decl.function.accessor.address"); -static UIdent KindRefAccessorAddress( - "source.lang.swift.ref.function.accessor.address"); -static UIdent KindDeclAccessorMutableAddress( - "source.lang.swift.decl.function.accessor.mutableaddress"); -static UIdent KindRefAccessorMutableAddress( - "source.lang.swift.ref.function.accessor.mutableaddress"); -static UIdent KindDeclConstructor("source.lang.swift.decl.function.constructor"); -static UIdent KindRefConstructor("source.lang.swift.ref.function.constructor"); -static UIdent KindDeclDestructor("source.lang.swift.decl.function.destructor"); -static UIdent KindRefDestructor("source.lang.swift.ref.function.destructor"); -static UIdent KindDeclFunctionPrefixOperator("source.lang.swift.decl.function.operator.prefix"); -static UIdent KindDeclFunctionPostfixOperator("source.lang.swift.decl.function.operator.postfix"); -static UIdent KindDeclFunctionInfixOperator("source.lang.swift.decl.function.operator.infix"); -static UIdent KindRefFunctionPrefixOperator("source.lang.swift.ref.function.operator.prefix"); -static UIdent KindRefFunctionPostfixOperator("source.lang.swift.ref.function.operator.postfix"); -static UIdent KindRefFunctionInfixOperator("source.lang.swift.ref.function.operator.infix"); -static UIdent KindDeclPrecedenceGroup("source.lang.swift.decl.precedencegroup"); -static UIdent KindRefPrecedenceGroup("source.lang.swift.ref.precedencegroup"); -static UIdent KindDeclSubscript("source.lang.swift.decl.function.subscript"); -static UIdent KindRefSubscript("source.lang.swift.ref.function.subscript"); -static UIdent KindDeclVarGlobal("source.lang.swift.decl.var.global"); -static UIdent KindRefVarGlobal("source.lang.swift.ref.var.global"); -static UIdent KindDeclVarInstance("source.lang.swift.decl.var.instance"); -static UIdent KindRefVarInstance("source.lang.swift.ref.var.instance"); -static UIdent KindDeclVarStatic("source.lang.swift.decl.var.static"); -static UIdent KindRefVarStatic("source.lang.swift.ref.var.static"); -static UIdent KindDeclVarClass("source.lang.swift.decl.var.class"); -static UIdent KindRefVarClass("source.lang.swift.ref.var.class"); -static UIdent KindDeclVarLocal("source.lang.swift.decl.var.local"); -static UIdent KindRefVarLocal("source.lang.swift.ref.var.local"); -static UIdent KindDeclVarParam("source.lang.swift.decl.var.parameter"); -static UIdent KindDeclModule("source.lang.swift.decl.module"); -static UIdent KindDeclClass("source.lang.swift.decl.class"); -static UIdent KindRefClass("source.lang.swift.ref.class"); -static UIdent KindDeclStruct("source.lang.swift.decl.struct"); -static UIdent KindRefStruct("source.lang.swift.ref.struct"); -static UIdent KindDeclEnum("source.lang.swift.decl.enum"); -static UIdent KindRefEnum("source.lang.swift.ref.enum"); -static UIdent KindDeclEnumCase("source.lang.swift.decl.enumcase"); -static UIdent KindDeclEnumElement("source.lang.swift.decl.enumelement"); -static UIdent KindRefEnumElement("source.lang.swift.ref.enumelement"); -static UIdent KindDeclProtocol("source.lang.swift.decl.protocol"); -static UIdent KindRefProtocol("source.lang.swift.ref.protocol"); -static UIdent KindDeclExtension("source.lang.swift.decl.extension"); -static UIdent KindDeclExtensionStruct("source.lang.swift.decl.extension.struct"); -static UIdent KindDeclExtensionClass("source.lang.swift.decl.extension.class"); -static UIdent KindDeclExtensionEnum("source.lang.swift.decl.extension.enum"); -static UIdent KindDeclExtensionProtocol("source.lang.swift.decl.extension.protocol"); -static UIdent KindDeclAssociatedType("source.lang.swift.decl.associatedtype"); -static UIdent KindRefAssociatedType("source.lang.swift.ref.associatedtype"); -static UIdent KindDeclTypeAlias("source.lang.swift.decl.typealias"); -static UIdent KindRefTypeAlias("source.lang.swift.ref.typealias"); -static UIdent KindDeclGenericTypeParam("source.lang.swift.decl.generic_type_param"); -static UIdent KindRefGenericTypeParam("source.lang.swift.ref.generic_type_param"); -static UIdent KindRefModule("source.lang.swift.ref.module"); -static UIdent KindStmtForEach("source.lang.swift.stmt.foreach"); -static UIdent KindStmtFor("source.lang.swift.stmt.for"); -static UIdent KindStmtWhile("source.lang.swift.stmt.while"); -static UIdent KindStmtRepeatWhile("source.lang.swift.stmt.repeatwhile"); -static UIdent KindStmtIf("source.lang.swift.stmt.if"); -static UIdent KindStmtGuard("source.lang.swift.stmt.guard"); -static UIdent KindStmtSwitch("source.lang.swift.stmt.switch"); -static UIdent KindStmtCase("source.lang.swift.stmt.case"); -static UIdent KindStmtBrace("source.lang.swift.stmt.brace"); -static UIdent KindExprCall("source.lang.swift.expr.call"); -static UIdent KindExprArg("source.lang.swift.expr.argument"); -static UIdent KindExprArray("source.lang.swift.expr.array"); -static UIdent KindExprDictionary("source.lang.swift.expr.dictionary"); -static UIdent KindExprObjectLiteral("source.lang.swift.expr.object_literal"); - -static UIdent KindStructureElemId("source.lang.swift.structure.elem.id"); -static UIdent KindStructureElemExpr("source.lang.swift.structure.elem.expr"); -static UIdent KindStructureElemInitExpr("source.lang.swift.structure.elem.init_expr"); -static UIdent KindStructureElemCondExpr("source.lang.swift.structure.elem.condition_expr"); -static UIdent KindStructureElemPattern("source.lang.swift.structure.elem.pattern"); -static UIdent KindStructureElemTypeRef("source.lang.swift.structure.elem.typeref"); - -static UIdent KindRangeSingleStatement("source.lang.swift.range.singlestatement"); -static UIdent KindRangeSingleExpression("source.lang.swift.range.singleexpression"); -static UIdent KindRangeSingleDeclaration("source.lang.swift.range.singledeclaration"); - -static UIdent KindRangeMultiStatement("source.lang.swift.range.multistatement"); - -static UIdent KindRangeInvalid("source.lang.swift.range.invalid"); - -static UIdent KindNameObjc("source.lang.name.kind.objc"); -static UIdent KindNameSwift("source.lang.name.kind.swift"); - +#define KIND(NAME, CONTENT) static UIdent Kind##NAME(CONTENT); +#include "SourceKit/Core/ProtocolUIDs.def" std::unique_ptr SourceKit::createSwiftLangSupport(SourceKit::Context &SKCtx) { @@ -416,24 +298,6 @@ UIdent SwiftLangSupport::getUIDForCodeCompletionDeclKind( } UIdent SwiftLangSupport::getUIDForSyntaxNodeKind(SyntaxNodeKind SC) { - static UIdent KindKeyword("source.lang.swift.syntaxtype.keyword"); - static UIdent KindIdentifier("source.lang.swift.syntaxtype.identifier"); - static UIdent KindTypeIdentifier("source.lang.swift.syntaxtype.typeidentifier"); - static UIdent KindBuildConfigKeyword("source.lang.swift.syntaxtype.buildconfig.keyword"); - static UIdent KindBuildConfigId("source.lang.swift.syntaxtype.buildconfig.id"); - static UIdent KindAttributeId("source.lang.swift.syntaxtype.attribute.id"); - static UIdent KindAttributeBuiltin("source.lang.swift.syntaxtype.attribute.builtin"); - static UIdent KindNumber("source.lang.swift.syntaxtype.number"); - static UIdent KindString("source.lang.swift.syntaxtype.string"); - static UIdent KindStringInterpolation("source.lang.swift.syntaxtype.string_interpolation_anchor"); - static UIdent KindComment("source.lang.swift.syntaxtype.comment"); - static UIdent KindDocComment("source.lang.swift.syntaxtype.doccomment"); - static UIdent KindDocCommentField("source.lang.swift.syntaxtype.doccomment.field"); - static UIdent KindCommentMarker("source.lang.swift.syntaxtype.comment.mark"); - static UIdent KindCommentURL("source.lang.swift.syntaxtype.comment.url"); - static UIdent KindPlaceholder("source.lang.swift.syntaxtype.placeholder"); - static UIdent KindObjectLiteral("source.lang.swift.syntaxtype.objectliteral"); - switch (SC) { case SyntaxNodeKind::Keyword: return KindKeyword; diff --git a/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp b/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp index 930160d853f..7b4ef2f00cf 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp @@ -1181,6 +1181,7 @@ static void resolveCursor(SwiftLangSupport &Lang, } return; } + case SemaTokenKind::ExprStart: case SemaTokenKind::StmtStart: { Receiver({}); return; @@ -1285,6 +1286,7 @@ static void resolveName(SwiftLangSupport &Lang, StringRef InputFile, } return; } + case SemaTokenKind::ExprStart: case SemaTokenKind::StmtStart: { Receiver({}); return; diff --git a/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp b/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp index f27ba1016b6..f2e15f10250 100644 --- a/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp +++ b/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp @@ -86,100 +86,15 @@ static void notification_receiver(sourcekitd_response_t resp); static SourceKitRequest ActiveRequest = SourceKitRequest::None; -static sourcekitd_uid_t KeyRequest; -static sourcekitd_uid_t KeyCompilerArgs; -static sourcekitd_uid_t KeyOffset; -static sourcekitd_uid_t KeySourceFile; -static sourcekitd_uid_t KeyModuleName; -static sourcekitd_uid_t KeyGroupName; -static sourcekitd_uid_t KeyLocalizationKey; -static sourcekitd_uid_t KeyActionName; -static sourcekitd_uid_t KeySynthesizedExtension; -static sourcekitd_uid_t KeyName; -static sourcekitd_uid_t KeyNames; -static sourcekitd_uid_t KeyFilePath; -static sourcekitd_uid_t KeyModuleInterfaceName; -static sourcekitd_uid_t KeyLength; -static sourcekitd_uid_t KeyActionable; -static sourcekitd_uid_t KeyParentLoc; -static sourcekitd_uid_t KeySourceText; -static sourcekitd_uid_t KeyUSR; -static sourcekitd_uid_t KeyOriginalUSR; -static sourcekitd_uid_t KeyDefaultImplementationOf; -static sourcekitd_uid_t KeyInterestedUSR; -static sourcekitd_uid_t KeyTypename; -static sourcekitd_uid_t KeyOverrides; -static sourcekitd_uid_t KeyRelatedDecls; -static sourcekitd_uid_t KeyAnnotatedDecl; -static sourcekitd_uid_t KeyFullyAnnotatedDecl; -static sourcekitd_uid_t KeyDocFullAsXML; -static sourcekitd_uid_t KeyResults; -static sourcekitd_uid_t KeySyntaxMap; -static sourcekitd_uid_t KeyEnableSyntaxMap; -static sourcekitd_uid_t KeyEnableSubStructure; -static sourcekitd_uid_t KeySyntacticOnly; -static sourcekitd_uid_t KeyLine; -static sourcekitd_uid_t KeyColumn; -static sourcekitd_uid_t KeyFormatOptions; -static sourcekitd_uid_t KeyCodeCompleteOptions; -static sourcekitd_uid_t KeyAnnotations; -static sourcekitd_uid_t KeyDiagnostics; -static sourcekitd_uid_t KeyDiagnosticStage; -static sourcekitd_uid_t KeySubStructure; -static sourcekitd_uid_t KeyIsSystem; -static sourcekitd_uid_t KeyNotification; -static sourcekitd_uid_t KeyPopular; -static sourcekitd_uid_t KeyUnpopular; -static sourcekitd_uid_t KeyTypeInterface; -static sourcekitd_uid_t KeyTypeUsr; -static sourcekitd_uid_t KeyContainerTypeUsr; -static sourcekitd_uid_t KeyModuleGroups; -static sourcekitd_uid_t KeySimplified; -static sourcekitd_uid_t KeyRangeContent; -static sourcekitd_uid_t KeyBaseName; -static sourcekitd_uid_t KeyArgNames; -static sourcekitd_uid_t KeySelectorPieces; -static sourcekitd_uid_t KeyIsZeroArgSelector; -static sourcekitd_uid_t KeyNameKind; -static sourcekitd_uid_t KeySwiftVersion; -static sourcekitd_uid_t KeyCancelOnSubsequentRequest; - -static sourcekitd_uid_t RequestProtocolVersion; -static sourcekitd_uid_t RequestDemangle; -static sourcekitd_uid_t RequestMangleSimpleClass; -static sourcekitd_uid_t RequestIndex; -static sourcekitd_uid_t RequestCodeComplete; -static sourcekitd_uid_t RequestCodeCompleteOpen; -static sourcekitd_uid_t RequestCodeCompleteClose; -static sourcekitd_uid_t RequestCodeCompleteUpdate; -static sourcekitd_uid_t RequestCodeCompleteCacheOnDisk; -static sourcekitd_uid_t RequestCodeCompleteSetPopularAPI; -static sourcekitd_uid_t RequestCursorInfo; -static sourcekitd_uid_t RequestRangeInfo; -static sourcekitd_uid_t RequestRelatedIdents; -static sourcekitd_uid_t RequestEditorOpen; -static sourcekitd_uid_t RequestEditorOpenInterface; -static sourcekitd_uid_t RequestEditorOpenSwiftSourceInterface; -static sourcekitd_uid_t RequestEditorOpenSwiftTypeInterface; -static sourcekitd_uid_t RequestEditorOpenHeaderInterface; -static sourcekitd_uid_t RequestEditorExtractTextFromComment; -static sourcekitd_uid_t RequestEditorReplaceText; -static sourcekitd_uid_t RequestEditorFormatText; -static sourcekitd_uid_t RequestEditorExpandPlaceholder; -static sourcekitd_uid_t RequestEditorFindUSR; -static sourcekitd_uid_t RequestEditorFindInterfaceDoc; -static sourcekitd_uid_t RequestDocInfo; -static sourcekitd_uid_t RequestModuleGroups; -static sourcekitd_uid_t RequestNameTranslation; -static sourcekitd_uid_t RequestMarkupToXML; +#define KEY(NAME, CONTENT) static sourcekitd_uid_t Key##NAME; +#define REQUEST(NAME, CONTENT) static sourcekitd_uid_t Request##NAME; +#define KIND(NAME, CONTENT) static sourcekitd_uid_t Kind##NAME; +#include "SourceKit/Core/ProtocolUIDs.def" static sourcekitd_uid_t SemaDiagnosticStage; static sourcekitd_uid_t NoteDocUpdate; -static sourcekitd_uid_t KindNameObjc; -static sourcekitd_uid_t KindNameSwift; - static SourceKit::Semaphore semaSemaphore(0); static sourcekitd_response_t semaResponse; static const char *semaName; @@ -216,102 +131,16 @@ static int skt_main(int argc, const char **argv) { notification_receiver(resp); }); - KeyRequest = sourcekitd_uid_get_from_cstr("key.request"); - KeyCompilerArgs = sourcekitd_uid_get_from_cstr("key.compilerargs"); - KeyOffset = sourcekitd_uid_get_from_cstr("key.offset"); - KeySourceFile = sourcekitd_uid_get_from_cstr("key.sourcefile"); - KeyModuleName = sourcekitd_uid_get_from_cstr("key.modulename"); - KeyGroupName = sourcekitd_uid_get_from_cstr("key.groupname"); - KeyLocalizationKey = sourcekitd_uid_get_from_cstr("key.localization_key"); - KeyActionName = sourcekitd_uid_get_from_cstr("key.actionname"); - KeySynthesizedExtension = sourcekitd_uid_get_from_cstr("key.synthesizedextensions"); - KeyName = sourcekitd_uid_get_from_cstr("key.name"); - KeyNames = sourcekitd_uid_get_from_cstr("key.names"); - KeyFilePath = sourcekitd_uid_get_from_cstr("key.filepath"); - KeyModuleInterfaceName = sourcekitd_uid_get_from_cstr("key.module_interface_name"); - KeyLength = sourcekitd_uid_get_from_cstr("key.length"); - KeyActionable = sourcekitd_uid_get_from_cstr("key.actionable"); - KeyParentLoc = sourcekitd_uid_get_from_cstr("key.parent_loc");; - KeySourceText = sourcekitd_uid_get_from_cstr("key.sourcetext"); - KeyUSR = sourcekitd_uid_get_from_cstr("key.usr"); - KeyOriginalUSR = sourcekitd_uid_get_from_cstr("key.original_usr"); - KeyDefaultImplementationOf = sourcekitd_uid_get_from_cstr("key.default_implementation_of"); - KeyInterestedUSR = sourcekitd_uid_get_from_cstr("key.interested_usr"); - KeyTypename = sourcekitd_uid_get_from_cstr("key.typename"); - KeyOverrides = sourcekitd_uid_get_from_cstr("key.overrides"); - KeyRelatedDecls = sourcekitd_uid_get_from_cstr("key.related_decls"); - KeyAnnotatedDecl = sourcekitd_uid_get_from_cstr("key.annotated_decl"); - KeyFullyAnnotatedDecl = - sourcekitd_uid_get_from_cstr("key.fully_annotated_decl"); - KeyDocFullAsXML = sourcekitd_uid_get_from_cstr("key.doc.full_as_xml"); - KeyResults = sourcekitd_uid_get_from_cstr("key.results"); - KeySyntaxMap = sourcekitd_uid_get_from_cstr("key.syntaxmap"); - KeyEnableSyntaxMap = sourcekitd_uid_get_from_cstr("key.enablesyntaxmap"); - KeyEnableSubStructure = sourcekitd_uid_get_from_cstr("key.enablesubstructure"); - KeySyntacticOnly = sourcekitd_uid_get_from_cstr("key.syntactic_only"); - KeyLine = sourcekitd_uid_get_from_cstr("key.line"); - KeyColumn = sourcekitd_uid_get_from_cstr("key.column"); - KeyFormatOptions = sourcekitd_uid_get_from_cstr("key.editor.format.options"); - KeyCodeCompleteOptions = - sourcekitd_uid_get_from_cstr("key.codecomplete.options"); - KeyAnnotations = sourcekitd_uid_get_from_cstr("key.annotations"); - KeyDiagnostics = sourcekitd_uid_get_from_cstr("key.diagnostics"); - KeyDiagnosticStage = sourcekitd_uid_get_from_cstr("key.diagnostic_stage"); - KeySubStructure = sourcekitd_uid_get_from_cstr("key.substructure"); - KeyIsSystem = sourcekitd_uid_get_from_cstr("key.is_system"); - KeyNotification = sourcekitd_uid_get_from_cstr("key.notification"); - KeyPopular = sourcekitd_uid_get_from_cstr("key.popular"); - KeyUnpopular = sourcekitd_uid_get_from_cstr("key.unpopular"); - KeyTypeInterface = sourcekitd_uid_get_from_cstr("key.typeinterface"); - KeyTypeUsr = sourcekitd_uid_get_from_cstr("key.typeusr"); - KeyContainerTypeUsr = sourcekitd_uid_get_from_cstr("key.containertypeusr"); - KeyModuleGroups = sourcekitd_uid_get_from_cstr("key.modulegroups"); - KeySimplified = sourcekitd_uid_get_from_cstr("key.simplified"); - KeyRangeContent = sourcekitd_uid_get_from_cstr("key.rangecontent"); - - KeyBaseName = sourcekitd_uid_get_from_cstr("key.basename"); - KeyArgNames = sourcekitd_uid_get_from_cstr("key.argnames"); - KeySelectorPieces = sourcekitd_uid_get_from_cstr("key.selectorpieces"); - KeyIsZeroArgSelector = sourcekitd_uid_get_from_cstr("key.is_zero_arg_selector"); - KeyNameKind = sourcekitd_uid_get_from_cstr("key.namekind"); - - KeySwiftVersion = sourcekitd_uid_get_from_cstr("key.swift_version"); - KeyCancelOnSubsequentRequest = sourcekitd_uid_get_from_cstr("key.cancel_on_subsequent_request"); +#define KEY(NAME, CONTENT) Key##NAME = sourcekitd_uid_get_from_cstr(CONTENT); +#include "SourceKit/Core/ProtocolUIDs.def" SemaDiagnosticStage = sourcekitd_uid_get_from_cstr("source.diagnostic.stage.swift.sema"); NoteDocUpdate = sourcekitd_uid_get_from_cstr("source.notification.editor.documentupdate"); - RequestProtocolVersion = sourcekitd_uid_get_from_cstr("source.request.protocol_version"); - RequestDemangle = sourcekitd_uid_get_from_cstr("source.request.demangle"); - RequestMangleSimpleClass = sourcekitd_uid_get_from_cstr("source.request.mangle_simple_class"); - RequestIndex = sourcekitd_uid_get_from_cstr("source.request.indexsource"); - RequestCodeComplete = sourcekitd_uid_get_from_cstr("source.request.codecomplete"); - RequestCodeCompleteOpen = sourcekitd_uid_get_from_cstr("source.request.codecomplete.open"); - RequestCodeCompleteClose = sourcekitd_uid_get_from_cstr("source.request.codecomplete.close"); - RequestCodeCompleteUpdate = sourcekitd_uid_get_from_cstr("source.request.codecomplete.update"); - RequestCodeCompleteCacheOnDisk = sourcekitd_uid_get_from_cstr("source.request.codecomplete.cache.ondisk"); - RequestCodeCompleteSetPopularAPI = sourcekitd_uid_get_from_cstr("source.request.codecomplete.setpopularapi"); - RequestCursorInfo = sourcekitd_uid_get_from_cstr("source.request.cursorinfo"); - RequestRangeInfo = sourcekitd_uid_get_from_cstr("source.request.rangeinfo"); - RequestRelatedIdents = sourcekitd_uid_get_from_cstr("source.request.relatedidents"); - RequestEditorOpen = sourcekitd_uid_get_from_cstr("source.request.editor.open"); - RequestEditorOpenInterface = sourcekitd_uid_get_from_cstr("source.request.editor.open.interface"); - RequestEditorOpenSwiftSourceInterface = sourcekitd_uid_get_from_cstr("source.request.editor.open.interface.swiftsource"); - RequestEditorOpenSwiftTypeInterface = sourcekitd_uid_get_from_cstr("source.request.editor.open.interface.swifttype"); - RequestEditorOpenHeaderInterface = sourcekitd_uid_get_from_cstr("source.request.editor.open.interface.header"); - RequestEditorExtractTextFromComment = sourcekitd_uid_get_from_cstr("source.request.editor.extract.comment"); - RequestEditorReplaceText = sourcekitd_uid_get_from_cstr("source.request.editor.replacetext"); - RequestEditorFormatText = sourcekitd_uid_get_from_cstr("source.request.editor.formattext"); - RequestEditorExpandPlaceholder = sourcekitd_uid_get_from_cstr("source.request.editor.expand_placeholder"); - RequestEditorFindUSR = sourcekitd_uid_get_from_cstr("source.request.editor.find_usr"); - RequestEditorFindInterfaceDoc = sourcekitd_uid_get_from_cstr("source.request.editor.find_interface_doc"); - RequestDocInfo = sourcekitd_uid_get_from_cstr("source.request.docinfo"); - RequestModuleGroups = sourcekitd_uid_get_from_cstr("source.request.module.groups"); - RequestNameTranslation = sourcekitd_uid_get_from_cstr("source.request.name.translation"); - RequestMarkupToXML = sourcekitd_uid_get_from_cstr("source.request.convert.markup.xml"); - KindNameObjc = sourcekitd_uid_get_from_cstr("source.lang.name.kind.objc"); - KindNameSwift = sourcekitd_uid_get_from_cstr("source.lang.name.kind.swift"); +#define REQUEST(NAME, CONTENT) Request##NAME = sourcekitd_uid_get_from_cstr(CONTENT); +#define KIND(NAME, CONTENT) Kind##NAME = sourcekitd_uid_get_from_cstr(CONTENT); +#include "SourceKit/Core/ProtocolUIDs.def" // A test invocation may initialize the options to be used for subsequent // invocations. @@ -665,7 +494,7 @@ static int handleTestInvocation(ArrayRef Args, sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestEditorOpen); sourcekitd_request_dictionary_set_string(Req, KeyName, SourceFile.c_str()); sourcekitd_request_dictionary_set_int64(Req, KeyEnableSyntaxMap, true); - sourcekitd_request_dictionary_set_int64(Req, KeyEnableSubStructure, false); + sourcekitd_request_dictionary_set_int64(Req, KeyEnableStructure, false); sourcekitd_request_dictionary_set_int64(Req, KeySyntacticOnly, !Opts.UsedSema); break; @@ -673,7 +502,7 @@ static int handleTestInvocation(ArrayRef Args, sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestEditorOpen); sourcekitd_request_dictionary_set_string(Req, KeyName, SourceFile.c_str()); sourcekitd_request_dictionary_set_int64(Req, KeyEnableSyntaxMap, false); - sourcekitd_request_dictionary_set_int64(Req, KeyEnableSubStructure, true); + sourcekitd_request_dictionary_set_int64(Req, KeyEnableStructure, true); sourcekitd_request_dictionary_set_int64(Req, KeySyntacticOnly, !Opts.UsedSema); break; @@ -681,7 +510,7 @@ static int handleTestInvocation(ArrayRef Args, sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestEditorOpen); sourcekitd_request_dictionary_set_string(Req, KeyName, SourceFile.c_str()); sourcekitd_request_dictionary_set_int64(Req, KeyEnableSyntaxMap, false); - sourcekitd_request_dictionary_set_int64(Req, KeyEnableSubStructure, false); + sourcekitd_request_dictionary_set_int64(Req, KeyEnableStructure, false); sourcekitd_request_dictionary_set_int64(Req, KeySyntacticOnly, !Opts.UsedSema); break; @@ -689,7 +518,7 @@ static int handleTestInvocation(ArrayRef Args, sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestEditorOpen); sourcekitd_request_dictionary_set_string(Req, KeyName, SourceFile.c_str()); sourcekitd_request_dictionary_set_int64(Req, KeyEnableSyntaxMap, false); - sourcekitd_request_dictionary_set_int64(Req, KeyEnableSubStructure, false); + sourcekitd_request_dictionary_set_int64(Req, KeyEnableStructure, false); sourcekitd_request_dictionary_set_int64(Req, KeySyntacticOnly, !Opts.UsedSema); break; @@ -991,7 +820,7 @@ static bool handleResponse(sourcekitd_response_t Resp, const TestOptions &Opts, bool EnableSubStructure = Opts.Request == SourceKitRequest::Structure; sourcekitd_request_dictionary_set_int64(EdReq, KeyEnableSyntaxMap, EnableSyntaxMax); - sourcekitd_request_dictionary_set_int64(EdReq, KeyEnableSubStructure, + sourcekitd_request_dictionary_set_int64(EdReq, KeyEnableStructure, EnableSubStructure); sourcekitd_request_dictionary_set_int64(EdReq, KeySyntacticOnly, !Opts.UsedSema); @@ -1055,26 +884,10 @@ sourcekitd_variant_t LatestSemaAnnotations = {{0,0,0}}; sourcekitd_variant_t LatestSemaDiags = {{0,0,0}}; static void getSemanticInfoImpl(sourcekitd_variant_t Info) { - sourcekitd_variant_t annotations = + LatestSemaAnnotations = sourcekitd_variant_dictionary_get_value(Info, KeyAnnotations); - sourcekitd_variant_t diagnosticStage = - sourcekitd_variant_dictionary_get_value(Info, KeyDiagnosticStage); - - auto hasSemaInfo = [&]{ - if (sourcekitd_variant_get_type(annotations) != SOURCEKITD_VARIANT_TYPE_NULL) - return true; - if (sourcekitd_variant_get_type(diagnosticStage) == SOURCEKITD_VARIANT_TYPE_UID) { - return sourcekitd_variant_uid_get_value(diagnosticStage) == SemaDiagnosticStage; - } - return false; - }; - - if (hasSemaInfo()) { - LatestSemaAnnotations = - sourcekitd_variant_dictionary_get_value(Info, KeyAnnotations); - LatestSemaDiags = - sourcekitd_variant_dictionary_get_value(Info, KeyDiagnostics); - } + LatestSemaDiags = + sourcekitd_variant_dictionary_get_value(Info, KeyDiagnostics); } static void getSemanticInfo(sourcekitd_variant_t Info, StringRef Filename) { @@ -1212,7 +1025,7 @@ static void printCursorInfo(sourcekitd_variant_t Info, StringRef FilenameIn, const char *USR = sourcekitd_variant_dictionary_get_string(Info, KeyUSR); const char *Name = sourcekitd_variant_dictionary_get_string(Info, KeyName); const char *Typename = sourcekitd_variant_dictionary_get_string(Info, - KeyTypename); + KeyTypeName); const char *TypeUsr = sourcekitd_variant_dictionary_get_string(Info, KeyTypeUsr); const char *ContainerTypeUsr = sourcekitd_variant_dictionary_get_string(Info, @@ -1373,7 +1186,7 @@ static void printRangeInfo(sourcekitd_variant_t Info, StringRef FilenameIn, } const char *Kind = sourcekitd_uid_get_string_ptr(KindUID); const char *Typename = sourcekitd_variant_dictionary_get_string(Info, - KeyTypename); + KeyTypeName); const char *RangeContent = sourcekitd_variant_dictionary_get_string(Info, KeyRangeContent); diff --git a/tools/SourceKit/tools/sourcekitd/lib/API/DictionaryKeys.h b/tools/SourceKit/tools/sourcekitd/lib/API/DictionaryKeys.h index ac16373dbfa..4a60d277be7 100644 --- a/tools/SourceKit/tools/sourcekitd/lib/API/DictionaryKeys.h +++ b/tools/SourceKit/tools/sourcekitd/lib/API/DictionaryKeys.h @@ -19,122 +19,8 @@ namespace SourceKit { namespace sourcekitd { -extern SourceKit::UIdent KeyVersionMajor; -extern SourceKit::UIdent KeyVersionMinor; -extern SourceKit::UIdent KeyResults; -extern SourceKit::UIdent KeyRequest; -extern SourceKit::UIdent KeyCompilerArgs; -extern SourceKit::UIdent KeyOffset; -extern SourceKit::UIdent KeySourceFile; -extern SourceKit::UIdent KeySourceText; -extern SourceKit::UIdent KeyModuleName; -extern SourceKit::UIdent KeyGroupName; -extern SourceKit::UIdent KeyActionName; -extern SourceKit::UIdent KeySynthesizedExtension; -extern SourceKit::UIdent KeyNotification; -extern SourceKit::UIdent KeyKeyword; -extern SourceKit::UIdent KeyName; -extern SourceKit::UIdent KeyNames; -extern SourceKit::UIdent KeyUIDs; -extern SourceKit::UIdent KeyEnableSyntaxMap; -extern SourceKit::UIdent KeyEnableDiagnostics; -extern SourceKit::UIdent KeySyntacticOnly; -extern SourceKit::UIdent KeyLength; -extern SourceKit::UIdent KeyActionable; -extern SourceKit::UIdent KeyParentLoc; -extern SourceKit::UIdent KeyKind; -extern SourceKit::UIdent KeyAccessibility; -extern SourceKit::UIdent KeySetterAccessibility; -extern SourceKit::UIdent KeyUSR; -extern SourceKit::UIdent KeyOriginalUSR; -extern SourceKit::UIdent KeyDefaultImplementationOf; -extern SourceKit::UIdent KeyInterestedUSR; -extern SourceKit::UIdent KeyLine; -extern SourceKit::UIdent KeyColumn; -extern SourceKit::UIdent KeyReceiverUSR; -extern SourceKit::UIdent KeyIsDynamic; -extern SourceKit::UIdent KeyIsTestCandidate; -extern SourceKit::UIdent KeyDescription; -extern SourceKit::UIdent KeyTypeName; -extern SourceKit::UIdent KeyRuntimeName; -extern SourceKit::UIdent KeySelectorName; -extern SourceKit::UIdent KeyOverrides; -extern SourceKit::UIdent KeyDocBrief; -extern SourceKit::UIdent KeyAssociatedUSRs; -extern SourceKit::UIdent KeyDocFullAsXML; -extern SourceKit::UIdent KeyGenericParams; -extern SourceKit::UIdent KeyGenericRequirements; -extern SourceKit::UIdent KeyAnnotatedDecl; -extern SourceKit::UIdent KeyFullyAnnotatedDecl; -extern SourceKit::UIdent KeyRelatedDecls; -extern SourceKit::UIdent KeyContext; -extern SourceKit::UIdent KeyModuleImportDepth; -extern SourceKit::UIdent KeyNumBytesToErase; -extern SourceKit::UIdent KeyNotRecommended; -extern SourceKit::UIdent KeyFilePath; -extern SourceKit::UIdent KeyModuleInterfaceName; -extern SourceKit::UIdent KeyHash; -extern SourceKit::UIdent KeyRelated; -extern SourceKit::UIdent KeyInherits; -extern SourceKit::UIdent KeyConforms; -extern SourceKit::UIdent KeyExtends; -extern SourceKit::UIdent KeyDependencies; -extern SourceKit::UIdent KeyEntities; -extern SourceKit::UIdent KeyDiagnostics; -extern SourceKit::UIdent KeySeverity; -extern SourceKit::UIdent KeyRanges; -extern SourceKit::UIdent KeyFixits; -extern SourceKit::UIdent KeyAnnotations; -extern SourceKit::UIdent KeyDiagnosticStage; -extern SourceKit::UIdent KeySyntaxMap; -extern SourceKit::UIdent KeyIsSystem; -extern SourceKit::UIdent KeyEnableStructure; -extern SourceKit::UIdent KeySubStructure; -extern SourceKit::UIdent KeyElements; -extern SourceKit::UIdent KeyNameOffset; -extern SourceKit::UIdent KeyNameLength; -extern SourceKit::UIdent KeyBodyOffset; -extern SourceKit::UIdent KeyBodyLength; -extern SourceKit::UIdent KeyThrowOffset; -extern SourceKit::UIdent KeyThrowLength; -extern SourceKit::UIdent KeyIsLocal; -extern SourceKit::UIdent KeyAttributes; -extern SourceKit::UIdent KeyAttribute; -extern SourceKit::UIdent KeyInheritedTypes; -extern SourceKit::UIdent KeyFormatOptions; -extern SourceKit::UIdent KeyCodeCompleteOptions; -extern SourceKit::UIdent KeyFilterRules; -extern SourceKit::UIdent KeyNextRequestStart; -extern SourceKit::UIdent KeyPopular; -extern SourceKit::UIdent KeyUnpopular; -extern SourceKit::UIdent KeyHide; -extern SourceKit::UIdent KeySimplified; - -extern SourceKit::UIdent KeyIsUnavailable; -extern SourceKit::UIdent KeyIsDeprecated; -extern SourceKit::UIdent KeyIsOptional; -extern SourceKit::UIdent KeyPlatform; -extern SourceKit::UIdent KeyMessage; -extern SourceKit::UIdent KeyIntroduced; -extern SourceKit::UIdent KeyDeprecated; -extern SourceKit::UIdent KeyObsoleted; -extern SourceKit::UIdent KeyRemoveCache; -extern SourceKit::UIdent KeyTypeInterface; -extern SourceKit::UIdent KeyTypeUsr; -extern SourceKit::UIdent KeyContainerTypeUsr; -extern SourceKit::UIdent KeyModuleGroups; - -extern SourceKit::UIdent KeyRangeContent; -extern SourceKit::UIdent KeyCancelOnSubsequentRequest; - -extern SourceKit::UIdent KeyBaseName; -extern SourceKit::UIdent KeyArgNames; -extern SourceKit::UIdent KeySelectorPieces; -extern SourceKit::UIdent KeyNameKind; -extern SourceKit::UIdent KeyLocalizationKey; -extern SourceKit::UIdent KeyIsZeroArgSelector; - -extern SourceKit::UIdent KeySwiftVersion; +#define KEY(NAME, CONTENT) extern SourceKit::UIdent Key##NAME; +#include "SourceKit/Core/ProtocolUIDs.def" /// \brief Used for determining the printing order of dictionary keys. bool compareDictKeys(SourceKit::UIdent LHS, SourceKit::UIdent RHS); diff --git a/tools/SourceKit/tools/sourcekitd/lib/API/Requests.cpp b/tools/SourceKit/tools/sourcekitd/lib/API/Requests.cpp index 6dc9d8b976c..720b731bd07 100644 --- a/tools/SourceKit/tools/sourcekitd/lib/API/Requests.cpp +++ b/tools/SourceKit/tools/sourcekitd/lib/API/Requests.cpp @@ -61,79 +61,16 @@ public: operator sourcekitd_uid_t() const { return get(); } + + StringRef str() const { + return StringRef(Name); + } }; } // anonymous namespace -static LazySKDUID RequestProtocolVersion("source.request.protocol_version"); - -static LazySKDUID RequestCrashWithExit("source.request.crash_exit"); - -static LazySKDUID RequestDemangle("source.request.demangle"); -static LazySKDUID RequestMangleSimpleClass("source.request.mangle_simple_class"); - -static LazySKDUID RequestIndex("source.request.indexsource"); -static LazySKDUID RequestDocInfo("source.request.docinfo"); -static LazySKDUID RequestCodeComplete("source.request.codecomplete"); -static LazySKDUID RequestCodeCompleteOpen("source.request.codecomplete.open"); -static LazySKDUID RequestCodeCompleteClose("source.request.codecomplete.close"); -static LazySKDUID - RequestCodeCompleteUpdate("source.request.codecomplete.update"); -static LazySKDUID - RequestCodeCompleteCacheOnDisk("source.request.codecomplete.cache.ondisk"); -static LazySKDUID RequestCodeCompleteSetPopularAPI( - "source.request.codecomplete.setpopularapi"); -static LazySKDUID - RequestCodeCompleteSetCustom("source.request.codecomplete.setcustom"); -static LazySKDUID RequestCursorInfo("source.request.cursorinfo"); -static LazySKDUID RequestRangeInfo("source.request.rangeinfo"); -static LazySKDUID RequestRelatedIdents("source.request.relatedidents"); -static LazySKDUID RequestEditorOpen("source.request.editor.open"); -static LazySKDUID RequestEditorOpenInterface( - "source.request.editor.open.interface"); -static LazySKDUID RequestEditorOpenHeaderInterface( - "source.request.editor.open.interface.header"); -static LazySKDUID RequestEditorOpenSwiftSourceInterface( - "source.request.editor.open.interface.swiftsource"); -static LazySKDUID RequestEditorOpenSwiftTypeInterface( - "source.request.editor.open.interface.swifttype"); -static LazySKDUID RequestEditorExtractTextFromComment( - "source.request.editor.extract.comment"); -static LazySKDUID RequestEditorClose("source.request.editor.close"); -static LazySKDUID RequestEditorReplaceText("source.request.editor.replacetext"); -static LazySKDUID RequestEditorFormatText("source.request.editor.formattext"); -static LazySKDUID RequestEditorExpandPlaceholder( - "source.request.editor.expand_placeholder"); -static LazySKDUID RequestEditorFindUSR("source.request.editor.find_usr"); -static LazySKDUID RequestEditorFindInterfaceDoc( - "source.request.editor.find_interface_doc"); -static LazySKDUID RequestBuildSettingsRegister( - "source.request.buildsettings.register"); -static LazySKDUID RequestModuleGroups( - "source.request.module.groups"); -static LazySKDUID RequestNameTranslation("source.request.name.translation"); -static LazySKDUID RequestMarkupToXML("source.request.convert.markup.xml"); - -static LazySKDUID KindExpr("source.lang.swift.expr"); -static LazySKDUID KindStmt("source.lang.swift.stmt"); -static LazySKDUID KindType("source.lang.swift.type"); - -static LazySKDUID KindEverything("source.codecompletion.everything"); -static LazySKDUID KindModule("source.codecompletion.module"); -static LazySKDUID KindKeyword("source.codecompletion.keyword"); -static LazySKDUID KindLiteral("source.codecompletion.literal"); -static LazySKDUID KindCustom("source.codecompletion.custom"); -static LazySKDUID KindIdentifier("source.codecompletion.identifier"); - -static UIdent DiagKindNote("source.diagnostic.severity.note"); -static UIdent DiagKindWarning("source.diagnostic.severity.warning"); -static UIdent DiagKindError("source.diagnostic.severity.error"); - - -static UIdent KindNameObjc("source.lang.name.kind.objc"); -static UIdent KindNameSwift("source.lang.name.kind.swift"); - -static LazySKDUID SwiftNameKind("source.lang.name.kind.swift"); -static LazySKDUID ObjcNameKind("source.lang.name.kind.objc"); +#define REQUEST(NAME, CONTENT) static LazySKDUID Request##NAME(CONTENT); +#define KIND(NAME, CONTENT) static LazySKDUID Kind##NAME(CONTENT); +#include "SourceKit/Core/ProtocolUIDs.def" static void onDocumentUpdateNotification(StringRef DocumentName) { static UIdent DocumentUpdateNotificationUID( @@ -815,10 +752,10 @@ handleSemanticRequest(RequestDict Req, if (!NK) { return Rec(createErrorRequestInvalid("'key.namekind' is required")); } - if (NK == SwiftNameKind) - Input.NameKind = KindNameSwift; - else if (NK == ObjcNameKind) - Input.NameKind = KindNameObjc; + if (NK == KindNameSwift.get()) + Input.NameKind = UIdent(KindNameSwift.str()); + else if (NK == KindNameObjc.get()) + Input.NameKind = UIdent(KindNameObjc.str()); else return Rec(createErrorRequestInvalid("'key.namekind' is unrecognizable")); if (auto Base = Req.getString(KeyBaseName)) { @@ -1375,10 +1312,10 @@ bool SKDocConsumer::handleDiagnostic(const DiagnosticEntryInfo &Info) { UIdent SeverityUID; switch (Info.Severity) { case DiagnosticSeverityKind::Warning: - SeverityUID = DiagKindWarning; + SeverityUID = UIdent(KindDiagWarning.str()); break; case DiagnosticSeverityKind::Error: - SeverityUID = DiagKindError; + SeverityUID = UIdent(KindDiagError.str()); break; } @@ -1389,7 +1326,7 @@ bool SKDocConsumer::handleDiagnostic(const DiagnosticEntryInfo &Info) { auto NotesArr = Elem.setArray(KeyDiagnostics); for (auto &NoteDiag : Info.Notes) { auto NoteElem = NotesArr.appendDictionary(); - NoteElem.set(KeySeverity, DiagKindNote); + NoteElem.set(KeySeverity, KindDiagNote); fillDictionaryForDiagnosticInfo(NoteElem, NoteDiag); } } @@ -1516,8 +1453,8 @@ static void reportNameInfo(const NameTranslatingInfo &Info, ResponseReceiver Rec Elem.set(KeyBaseName, Info.BaseName); } if (!Info.ArgNames.empty()) { - auto Arr = Elem.setArray(Info.NameKind == KindNameSwift ? KeyArgNames : - KeySelectorPieces); + auto Arr = Elem.setArray(Info.NameKind == UIdent(KindNameSwift.str()) ? + KeyArgNames : KeySelectorPieces); for (auto N : Info.ArgNames) { auto NameEle = Arr.appendDictionary(); NameEle.set(KeyName, N); @@ -1707,18 +1644,20 @@ static sourcekitd_response_t codeCompleteOpen(StringRef Name, optionsDict->dictionaryArrayApply(KeyFilterRules, [&](RequestDict dict) { FilterRule rule; auto kind = dict.getUID(KeyKind); - if (kind == KindEverything) { + if (kind == KindCodeCompletionEverything) { rule.kind = FilterRule::Everything; - } else if (kind == KindModule) { + } else if (kind == KindCodeCompletionModule) { rule.kind = FilterRule::Module; - } else if (kind == KindKeyword) { + } else if (kind == KindCodeCompletionKeyword) { rule.kind = FilterRule::Keyword; - } else if (kind == KindLiteral) { + } else if (kind == KindCodeCompletionLiteral) { rule.kind = FilterRule::Literal; - } else if (kind == KindCustom) { + } else if (kind == KindCodeCompletionCustom) { rule.kind = FilterRule::CustomCompletion; - } else if (kind == KindIdentifier) { + } else if (kind == KindCodeCompletionIdentifier) { rule.kind = FilterRule::Identifier; + } else if (kind == KindCodeCompletionDescription) { + rule.kind = FilterRule::Description; } else { // Warning: unknown } @@ -1746,6 +1685,16 @@ static sourcekitd_response_t codeCompleteOpen(StringRef Name, rule.names.assign(names.begin(), names.end()); break; } + case FilterRule::Description: { + SmallVector names; + if (dict.getStringArray(KeyNames, names, false)) { + failed = true; + CCC.failed("filter rule missing required key 'key.names'"); + return true; + } + rule.names.assign(names.begin(), names.end()); + break; + } case FilterRule::Keyword: case FilterRule::Literal: case FilterRule::CustomCompletion: { @@ -2257,10 +2206,10 @@ bool SKEditorConsumer::handleDiagnostic(const DiagnosticEntryInfo &Info, UIdent SeverityUID; switch (Info.Severity) { case DiagnosticSeverityKind::Warning: - SeverityUID = DiagKindWarning; + SeverityUID = UIdent(KindDiagWarning.str()); break; case DiagnosticSeverityKind::Error: - SeverityUID = DiagKindError; + SeverityUID = UIdent(KindDiagError.str()); break; } @@ -2272,7 +2221,7 @@ bool SKEditorConsumer::handleDiagnostic(const DiagnosticEntryInfo &Info, auto NotesArr = Elem.setArray(KeyDiagnostics); for (auto &NoteDiag : Info.Notes) { auto NoteElem = NotesArr.appendDictionary(); - NoteElem.set(KeySeverity, DiagKindNote); + NoteElem.set(KeySeverity, KindDiagNote); fillDictionaryForDiagnosticInfo(NoteElem, NoteDiag); } } diff --git a/tools/SourceKit/tools/sourcekitd/lib/API/sourcekitdAPI-Common.cpp b/tools/SourceKit/tools/sourcekitd/lib/API/sourcekitdAPI-Common.cpp index 9eb18f5bbe7..fe65dea3d9e 100644 --- a/tools/SourceKit/tools/sourcekitd/lib/API/sourcekitdAPI-Common.cpp +++ b/tools/SourceKit/tools/sourcekitd/lib/API/sourcekitdAPI-Common.cpp @@ -32,225 +32,14 @@ using llvm::ArrayRef; using llvm::StringRef; using llvm::raw_ostream; - -UIdent sourcekitd::KeyVersionMajor("key.version_major");; -UIdent sourcekitd::KeyVersionMinor("key.version_minor");; -UIdent sourcekitd::KeyResults("key.results"); -UIdent sourcekitd::KeyRequest("key.request"); -UIdent sourcekitd::KeyCompilerArgs("key.compilerargs"); -UIdent sourcekitd::KeyOffset("key.offset"); -UIdent sourcekitd::KeySourceFile("key.sourcefile"); -UIdent sourcekitd::KeySourceText("key.sourcetext"); -UIdent sourcekitd::KeyModuleName("key.modulename"); -UIdent sourcekitd::KeyGroupName("key.groupname"); -UIdent sourcekitd::KeyActionName("key.actionname"); -UIdent sourcekitd::KeySynthesizedExtension("key.synthesizedextensions"); -UIdent sourcekitd::KeyNotification("key.notification"); -UIdent sourcekitd::KeyKeyword("key.keyword"); -UIdent sourcekitd::KeyName("key.name"); -UIdent sourcekitd::KeyNames("key.names"); -UIdent sourcekitd::KeyUIDs("key.uids"); -UIdent sourcekitd::KeyEnableSyntaxMap("key.enablesyntaxmap"); -UIdent sourcekitd::KeyEnableDiagnostics("key.enablediagnostics"); -UIdent sourcekitd::KeySyntacticOnly("key.syntactic_only"); -UIdent sourcekitd::KeyLength("key.length"); -UIdent sourcekitd::KeyActionable("key.actionable"); -UIdent sourcekitd::KeyParentLoc("key.parent_loc"); -UIdent sourcekitd::KeyKind("key.kind"); -UIdent sourcekitd::KeyAccessibility("key.accessibility"); -UIdent sourcekitd::KeySetterAccessibility("key.setter_accessibility"); -UIdent sourcekitd::KeyUSR("key.usr"); -UIdent sourcekitd::KeyOriginalUSR("key.original_usr"); -UIdent sourcekitd::KeyDefaultImplementationOf("key.default_implementation_of"); -UIdent sourcekitd::KeyInterestedUSR("key.interested_usr"); -UIdent sourcekitd::KeyLine("key.line"); -UIdent sourcekitd::KeyColumn("key.column"); -UIdent sourcekitd::KeyReceiverUSR("key.receiver_usr"); -UIdent sourcekitd::KeyIsDynamic("key.is_dynamic"); -UIdent sourcekitd::KeyIsTestCandidate("key.is_test_candidate"); -UIdent sourcekitd::KeyDescription("key.description"); -UIdent sourcekitd::KeyTypeName("key.typename"); -UIdent sourcekitd::KeyRuntimeName("key.runtime_name"); -UIdent sourcekitd::KeySelectorName("key.selector_name"); -UIdent sourcekitd::KeyOverrides("key.overrides"); -UIdent sourcekitd::KeyDocBrief("key.doc.brief"); -UIdent sourcekitd::KeyAssociatedUSRs("key.associated_usrs"); -UIdent sourcekitd::KeyDocFullAsXML("key.doc.full_as_xml"); -UIdent sourcekitd::KeyGenericParams("key.generic_params"); -UIdent sourcekitd::KeyGenericRequirements("key.generic_requirements"); -UIdent sourcekitd::KeyAnnotatedDecl("key.annotated_decl"); -UIdent sourcekitd::KeyFullyAnnotatedDecl("key.fully_annotated_decl"); -UIdent sourcekitd::KeyRelatedDecls("key.related_decls"); -UIdent sourcekitd::KeyContext("key.context"); -UIdent sourcekitd::KeyModuleImportDepth("key.moduleimportdepth"); -UIdent sourcekitd::KeyNumBytesToErase("key.num_bytes_to_erase"); -UIdent sourcekitd::KeyNotRecommended("key.not_recommended"); -UIdent sourcekitd::KeyFilePath("key.filepath"); -UIdent sourcekitd::KeyModuleInterfaceName("key.module_interface_name"); -UIdent sourcekitd::KeyHash("key.hash"); -UIdent sourcekitd::KeyRelated("key.related"); -UIdent sourcekitd::KeyInherits("key.inherits"); -UIdent sourcekitd::KeyConforms("key.conforms"); -UIdent sourcekitd::KeyExtends("key.extends"); -UIdent sourcekitd::KeyDependencies("key.dependencies"); -UIdent sourcekitd::KeyEntities("key.entities"); -UIdent sourcekitd::KeyDiagnostics("key.diagnostics"); -UIdent sourcekitd::KeySeverity("key.severity"); -UIdent sourcekitd::KeyRanges("key.ranges"); -UIdent sourcekitd::KeyFixits("key.fixits"); -UIdent sourcekitd::KeyAnnotations("key.annotations"); -UIdent sourcekitd::KeyDiagnosticStage("key.diagnostic_stage"); -UIdent sourcekitd::KeySyntaxMap("key.syntaxmap"); -UIdent sourcekitd::KeyIsSystem("key.is_system"); -UIdent sourcekitd::KeyEnableStructure("key.enablesubstructure"); -UIdent sourcekitd::KeySubStructure("key.substructure"); -UIdent sourcekitd::KeyElements("key.elements"); -UIdent sourcekitd::KeyNameOffset("key.nameoffset"); -UIdent sourcekitd::KeyNameLength("key.namelength"); -UIdent sourcekitd::KeyBodyOffset("key.bodyoffset"); -UIdent sourcekitd::KeyBodyLength("key.bodylength"); -UIdent sourcekitd::KeyThrowOffset("key.throwoffset"); -UIdent sourcekitd::KeyThrowLength("key.throwlength"); -UIdent sourcekitd::KeyIsLocal("key.is_local"); -UIdent sourcekitd::KeyAttributes("key.attributes"); -UIdent sourcekitd::KeyAttribute("key.attribute"); -UIdent sourcekitd::KeyInheritedTypes("key.inheritedtypes"); -UIdent sourcekitd::KeyFormatOptions("key.editor.format.options"); -UIdent sourcekitd::KeyCodeCompleteOptions("key.codecomplete.options"); -UIdent sourcekitd::KeyFilterRules("key.codecomplete.filterrules"); -UIdent sourcekitd::KeyNextRequestStart("key.nextrequeststart"); -UIdent sourcekitd::KeyPopular("key.popular"); -UIdent sourcekitd::KeyUnpopular("key.unpopular"); -UIdent sourcekitd::KeyHide("key.hide"); -UIdent sourcekitd::KeySimplified("key.simplified"); -UIdent sourcekitd::KeyRangeContent("key.rangecontent"); -UIdent sourcekitd::KeyCancelOnSubsequentRequest("key.cancel_on_subsequent_request"); - -UIdent sourcekitd::KeyIsDeprecated("key.is_deprecated"); -UIdent sourcekitd::KeyIsUnavailable("key.is_unavailable"); -UIdent sourcekitd::KeyIsOptional("key.is_optional"); -UIdent sourcekitd::KeyPlatform("key.platform"); -UIdent sourcekitd::KeyMessage("key.message"); -UIdent sourcekitd::KeyIntroduced("key.introduced"); -UIdent sourcekitd::KeyDeprecated("key.deprecated"); -UIdent sourcekitd::KeyObsoleted("key.obsoleted"); -UIdent sourcekitd::KeyRemoveCache("key.removecache"); -UIdent sourcekitd::KeyTypeInterface("key.typeinterface"); -UIdent sourcekitd::KeyTypeUsr("key.typeusr"); -UIdent sourcekitd::KeyContainerTypeUsr("key.containertypeusr"); -UIdent sourcekitd::KeyModuleGroups("key.modulegroups"); - -UIdent sourcekitd::KeyBaseName("key.basename"); -UIdent sourcekitd::KeyArgNames("key.argnames"); -UIdent sourcekitd::KeySelectorPieces("key.selectorpieces"); -UIdent sourcekitd::KeyNameKind("key.namekind"); -UIdent sourcekitd::KeyLocalizationKey("key.localization_key"); -UIdent sourcekitd::KeyIsZeroArgSelector("key.is_zero_arg_selector"); - -UIdent sourcekitd::KeySwiftVersion("key.swift_version"); +#define KEY(NAME, CONTENT) UIdent sourcekitd::Key##NAME(CONTENT); +#include "SourceKit/Core/ProtocolUIDs.def" /// \brief Order for the keys to use when emitting the debug description of /// dictionaries. static UIdent *OrderedKeys[] = { - &KeyVersionMajor, - &KeyVersionMinor, - &KeyResults, - &KeyRequest, - &KeyNotification, - &KeyKind, - &KeyAccessibility, - &KeySetterAccessibility, - &KeyKeyword, - &KeyName, - &KeyUSR, - &KeyOriginalUSR, - &KeyDefaultImplementationOf, - &KeyInterestedUSR, - &KeyGenericParams, - &KeyGenericRequirements, - &KeyDocFullAsXML, - &KeyLine, - &KeyColumn, - &KeyReceiverUSR, - &KeyIsDynamic, - &KeyFilePath, - &KeyModuleInterfaceName, - &KeyHash, - &KeyCompilerArgs, - &KeySeverity, - &KeyOffset, - &KeyLength, - &KeySourceFile, - &KeySourceText, - &KeyEnableSyntaxMap, - &KeyEnableStructure, - &KeyDescription, - &KeyTypeName, - &KeyRuntimeName, - &KeySelectorName, - &KeyAnnotatedDecl, - &KeyFullyAnnotatedDecl, - &KeyDocBrief, - &KeyContext, - &KeyModuleImportDepth, - &KeyNumBytesToErase, - &KeyNotRecommended, - &KeyAnnotations, - &KeyDiagnosticStage, - &KeySyntaxMap, - &KeyIsSystem, - &KeyRelated, - &KeyInherits, - &KeyConforms, - &KeyExtends, - &KeyDependencies, - &KeyEntities, - &KeyNameOffset, - &KeyNameLength, - &KeyBodyOffset, - &KeyBodyLength, - &KeyThrowOffset, - &KeyThrowLength, - &KeyIsLocal, - &KeyInheritedTypes, - &KeyAttributes, - &KeyAttribute, - &KeyElements, - &KeySubStructure, - &KeyRanges, - &KeyFixits, - &KeyDiagnostics, - &KeyFormatOptions, - &KeyCodeCompleteOptions, - &KeyFilterRules, - &KeyNextRequestStart, - &KeyPopular, - &KeyUnpopular, - &KeyHide, - - &KeyPlatform, - &KeyIsDeprecated, - &KeyIsUnavailable, - &KeyIsOptional, - &KeyMessage, - &KeyIntroduced, - &KeyDeprecated, - &KeyObsoleted, - &KeyRemoveCache, - - &KeyTypeInterface, - &KeyTypeUsr, - &KeyContainerTypeUsr, - &KeyModuleGroups, - - &KeyBaseName, - &KeyArgNames, - &KeySelectorPieces, - &KeyNameKind, - &KeyLocalizationKey, - &KeyIsZeroArgSelector, - - &KeySwiftVersion, +#define KEY(NAME, CONTENT) &Key##NAME, +#include "SourceKit/Core/ProtocolUIDs.def" }; static unsigned findPrintOrderForDictKey(UIdent Key) { diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt index ef4fd1ce935..cd9f779ae9c 100644 --- a/tools/driver/CMakeLists.txt +++ b/tools/driver/CMakeLists.txt @@ -31,6 +31,10 @@ swift_create_post_build_symlink(swift DESTINATION "swift-autolink-extract${CMAKE_EXECUTABLE_SUFFIX}" WORKING_DIRECTORY "${SWIFT_RUNTIME_OUTPUT_INTDIR}") +add_swift_tool_symlink(swiftc swift compiler) +add_swift_tool_symlink(swift-autolink-extract swift autolink-driver) +add_swift_tool_symlink(swift-format swift editor-integration) + # If building as part of clang, make sure the headers are installed. if(NOT SWIFT_BUILT_STANDALONE) add_dependencies(swift clang-headers) diff --git a/tools/sil-opt/SILOpt.cpp b/tools/sil-opt/SILOpt.cpp index 311d0260e0f..7874c8b5262 100644 --- a/tools/sil-opt/SILOpt.cpp +++ b/tools/sil-opt/SILOpt.cpp @@ -95,7 +95,7 @@ enum EnforceExclusivityMode { static cl::opt EnforceExclusivity( "enforce-exclusivity", cl::desc("Enforce law of exclusivity " "(and support memory access markers)."), - cl::init(EnforceExclusivityMode::None), + cl::init(EnforceExclusivityMode::Checked), cl::values(clEnumValN(EnforceExclusivityMode::Unchecked, "unchecked", "Static checking only."), clEnumValN(EnforceExclusivityMode::Checked, "checked", @@ -289,12 +289,7 @@ int main(int argc, char **argv) { SILOpts.AssumeUnqualifiedOwnershipWhenParsing = AssumeUnqualifiedOwnershipWhenParsing; - if (EnforceExclusivity.getNumOccurrences() == 0) { - if (SILOpts.Optimization > SILOptions::SILOptMode::None) { - SILOpts.EnforceExclusivityStatic = false; - SILOpts.EnforceExclusivityDynamic = false; - } - } else { + if (EnforceExclusivity.getNumOccurrences() != 0) { switch (EnforceExclusivity) { case EnforceExclusivityMode::Unchecked: // This option is analogous to the -Ounchecked optimization setting. diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp index 80533ca7671..d7ce1465fa9 100644 --- a/tools/swift-api-digester/swift-api-digester.cpp +++ b/tools/swift-api-digester/swift-api-digester.cpp @@ -299,12 +299,15 @@ struct SDKNodeInitInfo { Ownership Ownership = Ownership::Strong; std::vector DeclAttrs; std::vector TypeAttrs; + StringRef SuperclassUsr; SDKNodeInitInfo(SDKContext &Ctx) : Ctx(Ctx) {} SDKNodeInitInfo(SDKContext &Ctx, ValueDecl *VD); SDKNodeInitInfo(SDKContext &Ctx, Type Ty); SDKNode* createSDKNode(SDKNodeKind Kind); }; +class SDKNodeRoot; + class SDKNode { typedef std::vector::iterator ChildIt; SDKContext &Ctx; @@ -351,6 +354,7 @@ public: unsigned getChildIndex(NodePtr Child) const; const SDKNode* getOnlyChild() const; SDKContext &getSDKContext() const { return Ctx; } + SDKNodeRoot *getRootNode() const; template const T *getAs() const; template T *getAs(); }; @@ -388,6 +392,27 @@ public: bool isStatic() const { return IsStatic; }; }; +class SDKNodeRoot :public SDKNode { + /// This keeps track of all decl descendants with USRs. + llvm::StringMap DescendantDeclTable; + +public: + SDKNodeRoot(SDKNodeInitInfo Info) : SDKNode(Info, SDKNodeKind::Root) {} + static SDKNode *getInstance(SDKContext &Ctx); + static bool classof(const SDKNode *N); + void registerDescendant(SDKNode *D) { + if (auto DD = dyn_cast(D)) { + assert(!DD->getUsr().empty()); + DescendantDeclTable[DD->getUsr()] = DD; + } + } + Optional getDescendantByUsr(StringRef Usr) { + if (DescendantDeclTable.count(Usr)) + return DescendantDeclTable[Usr]; + return None; + } +}; + NodePtr UpdatedNodesMap::findUpdateCounterpart(const SDKNode *Node) const { assert(Node->isAnnotatedAs(NodeAnnotation::Updated) && "Not update operation."); auto FoundPair = std::find_if(MapImpl.begin(), MapImpl.end(), @@ -474,9 +499,27 @@ const SDKNode* SDKNode::getOnlyChild() const { return *Children.begin(); } +SDKNodeRoot *SDKNode::getRootNode() const { + for (auto *Root = const_cast(this); ; Root = Root->getParent()) { + if (auto Result = dyn_cast(Root)) + return Result; + } + llvm_unreachable("Unhandled SDKNodeKind in switch."); +} + void SDKNode::addChild(SDKNode *Child) { Child->Parent = this; Children.push_back(Child); + if (auto *Root = dyn_cast(this)) { + struct DeclCollector: public SDKNodeVisitor { + SDKNodeRoot &Root; + DeclCollector(SDKNodeRoot &Root): Root(Root) {} + void visit(NodePtr Node) override { + Root.registerDescendant(Node); + } + } Collector(*Root); + SDKNode::preorderVisit(Child, Collector); + } } ArrayRef SDKNode::getChildren() const { @@ -601,13 +644,6 @@ bool SDKNodeType::hasTypeAttribute(TypeAttrKind DAKind) const { TypeAttributes.end(); } -class SDKNodeRoot : public SDKNode { -public: - SDKNodeRoot(SDKNodeInitInfo Info) : SDKNode(Info, SDKNodeKind::Root) {} - static SDKNode *getInstance(SDKContext &Ctx); - static bool classof(const SDKNode *N); -}; - SDKNode *SDKNodeRoot::getInstance(SDKContext &Ctx) { SDKNodeInitInfo Info(Ctx); Info.Name = Ctx.buffer("TopLevel"); @@ -683,10 +719,33 @@ SDKNodeDecl *SDKNodeType::getClosestParentDecl() const { } class SDKNodeTypeDecl : public SDKNodeDecl { + StringRef SuperclassUsr; public: - SDKNodeTypeDecl(SDKNodeInitInfo Info) : SDKNodeDecl(Info, - SDKNodeKind::TypeDecl) {} + SDKNodeTypeDecl(SDKNodeInitInfo Info) : SDKNodeDecl(Info, SDKNodeKind::TypeDecl), + SuperclassUsr(Info.SuperclassUsr) {} static bool classof(const SDKNode *N); + StringRef getSuperClassUsr() const { return SuperclassUsr; } + + Optional getSuperclass() const { + if (SuperclassUsr.empty()) + return None; + return (*getRootNode()->getDescendantByUsr(SuperclassUsr))-> + getAs(); + } + + /// Finding the node through all children, including the inheritted ones, + /// whose printed name matches with the given name. + Optional lookupChildByPrintedName(StringRef Name) const { + for (auto C : getChildren()) { + if (C->getPrintedName() == Name) + return C->getAs(); + } + // Finding from the inheritance chain. + if (auto Super = getSuperclass()) { + return (*Super)->lookupChildByPrintedName(Name); + } + return None; + } }; class SDKNodeTypeAlias : public SDKNodeDecl { @@ -828,6 +887,9 @@ SDKNode* SDKNode::constructSDKNode(SDKContext &Ctx, case KeyKind::KK_moduleName: Info.ModuleName = GetScalarString(Pair.getValue()); break; + case KeyKind::KK_superclassUsr: + Info.SuperclassUsr = GetScalarString(Pair.getValue()); + break; case KeyKind::KK_throwing: Info.IsThrowing = true; break; @@ -1092,6 +1154,12 @@ SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, ValueDecl *VD) : Ctx(Ctx), IsThrowing(isFuncThrowing(VD)), IsMutating(isFuncMutating(VD)), IsStatic(VD->isStatic()), SelfIndex(getSelfIndex(VD)), Ownership(getOwnership(VD)) { + + // Calculate usr for its super class. + if (auto *CD = dyn_cast_or_null(VD)) { + if (auto *Super = CD->getSuperclassDecl()) + SuperclassUsr = calculateUsr(Ctx, Super); + } if (VD->getAttrs().getDeprecated(VD->getASTContext())) DeclAttrs.push_back(SDKDeclAttrKind::DAK_deprecated); } @@ -1331,7 +1399,8 @@ public: llvm::array_pod_sort(ClangMacros.begin(), ClangMacros.end(), [](ValueDecl * const *lhs, ValueDecl * const *rhs) -> int { - return (*lhs)->getNameStr().compare((*rhs)->getNameStr()); + return (*lhs)->getBaseName().userFacingName().compare( + (*rhs)->getBaseName().userFacingName()); }); for (auto *VD : ClangMacros) @@ -1441,6 +1510,13 @@ namespace swift { Index); } } + if (auto *TD = dyn_cast(value)) { + auto Super = TD->getSuperClassUsr(); + if (!Super.empty()) { + out.mapRequired(getKeyContent(Ctx, KeyKind::KK_superclassUsr).data(), + Super); + } + } auto Attributes = D->getDeclAttributes(); if (!Attributes.empty()) out.mapRequired(getKeyContent(Ctx, KeyKind::KK_declAttributes).data(), @@ -2666,7 +2742,8 @@ void DiagnosisEmitter::collectAddedDecls(NodePtr Root, SDKNodeDecl *DiagnosisEmitter::findAddedDecl(const SDKNodeDecl *Root) { for (auto *Added : AddedDecls) { if (Root->getKind() == Added->getKind() && - Root->getPrintedName() == Added->getPrintedName()) + Root->getPrintedName() == Added->getPrintedName() && + Root->getUsr() == Added->getUsr()) return Added; } return nullptr; @@ -2776,6 +2853,22 @@ void DiagnosisEmitter::handle(const SDKNodeDecl *Node, NodeAnnotation Anno) { return; } } + + // We should exlude those declarations that are pulled up to the super classes. + bool FoundInSuperclass = false; + if (auto PD = dyn_cast(Node->getParent())) { + if (PD->isAnnotatedAs(NodeAnnotation::Updated)) { + // Get the updated counterpart of the parent decl. + if (auto RTD = dyn_cast(UpdateMap. + findUpdateCounterpart(PD))) { + // Look up by the printed name in the counterpart. + FoundInSuperclass = + RTD->lookupChildByPrintedName(Node->getPrintedName()).hasValue(); + } + } + } + if (FoundInSuperclass) + return; RemovedDecls.Diags.emplace_back(Node->getDeclKind(), Node->getFullyQualifiedName(), Node->isDeprecated()); diff --git a/tools/swift-demangle/swift-demangle.cpp b/tools/swift-demangle/swift-demangle.cpp index b8d6b95feb6..98d5fb7e81b 100644 --- a/tools/swift-demangle/swift-demangle.cpp +++ b/tools/swift-demangle/swift-demangle.cpp @@ -102,12 +102,15 @@ static void demangle(llvm::raw_ostream &os, llvm::StringRef name, remangled = name; } else { remangled = swift::Demangle::mangleNode(pointer); - // Also accept the future mangling prefix. - // TODO: remove the special "_S" handling as soon as MANGLING_PREFIX_STR - // gets "_S". - if (name.startswith("_S")) { - assert(remangled.find(MANGLING_PREFIX_STR) == 0); - remangled = "_S" + remangled.substr(3); + unsigned prefixLen = swift::Demangle::getManglingPrefixLength(remangled.data()); + assert(prefixLen > 0); + // Replace the prefix if we remangled with a different prefix. + if (!name.startswith(remangled.substr(0, prefixLen))) { + unsigned namePrefixLen = + swift::Demangle::getManglingPrefixLength(name.data()); + assert(namePrefixLen > 0); + remangled = name.take_front(namePrefixLen).str() + + remangled.substr(prefixLen); } if (name != remangled) { llvm::errs() << "\nError: re-mangled name \n " << remangled @@ -163,7 +166,7 @@ static int demangleSTDIN(const swift::Demangle::DemangleOptions &options) { // This doesn't handle Unicode symbols, but maybe that's okay. // Also accept the future mangling prefix. // TODO: remove the "_S" as soon as MANGLING_PREFIX_STR gets "_S". - llvm::Regex maybeSymbol("(_T|_S|" MANGLING_PREFIX_STR ")[_a-zA-Z0-9$]+"); + llvm::Regex maybeSymbol("(_T|_*\\$S|" MANGLING_PREFIX_STR ")[_a-zA-Z0-9$.]+"); swift::Demangle::Context DCtx; for (std::string mangled; std::getline(std::cin, mangled);) { diff --git a/tools/swift-syntax-test/swift-syntax-test.cpp b/tools/swift-syntax-test/swift-syntax-test.cpp index 31703003293..427b5a1d751 100644 --- a/tools/swift-syntax-test/swift-syntax-test.cpp +++ b/tools/swift-syntax-test/swift-syntax-test.cpp @@ -27,6 +27,7 @@ #include "swift/Parse/Lexer.h" #include "swift/Subsystems.h" #include "swift/Syntax/LegacyASTTransformer.h" +#include "swift/Syntax/Serialization/SyntaxSerialization.h" #include "swift/Syntax/SyntaxData.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" @@ -36,9 +37,10 @@ using namespace swift; using llvm::StringRef; enum class ActionType { - DumpTokenSyntax, + DumpRawTokenSyntax, FullLexRoundTrip, FullParseRoundTrip, + SerializeRawTree, None }; @@ -47,7 +49,7 @@ static llvm::cl::opt Action(llvm::cl::desc("Action (required):"), llvm::cl::init(ActionType::None), llvm::cl::values( - clEnumValN(ActionType::DumpTokenSyntax, + clEnumValN(ActionType::DumpRawTokenSyntax, "dump-full-tokens", "Lex the source file and dump the tokens " "and their absolute line/column locations"), @@ -58,7 +60,11 @@ Action(llvm::cl::desc("Action (required):"), clEnumValN(ActionType::FullParseRoundTrip, "round-trip-parse", "Parse the source file and print it back out for " - "comparing against the input"))); + "comparing against the input"), + clEnumValN(ActionType::SerializeRawTree, + "serialize-raw-tree", + "Parse the source file and serialize the raw tree" + "to JSON"))); static llvm::cl::opt InputSourceFilename("input-source-filename", @@ -69,7 +75,7 @@ int getTokensFromFile(unsigned BufferID, LangOptions &LangOpts, SourceManager &SourceMgr, DiagnosticEngine &Diags, - std::vector, + std::vector, syntax::AbsolutePosition>> &Tokens) { Tokens = tokenizeWithTrivia(LangOpts, SourceMgr, BufferID); return Diags.hadAnyError() ? EXIT_FAILURE : EXIT_SUCCESS; @@ -81,7 +87,7 @@ getTokensFromFile(const StringRef InputFilename, LangOptions &LangOpts, SourceManager &SourceMgr, DiagnosticEngine &Diags, - std::vector, + std::vector, syntax::AbsolutePosition>> &Tokens) { auto Buffer = llvm::MemoryBuffer::getFile(InputFilename); if (!Buffer) { @@ -94,57 +100,22 @@ getTokensFromFile(const StringRef InputFilename, return getTokensFromFile(BufferID, LangOpts, SourceMgr, Diags, Tokens); } -int doFullLexRoundTrip(const StringRef InputFilename) { - LangOptions LangOpts; - SourceManager SourceMgr; - DiagnosticEngine Diags(SourceMgr); - PrintingDiagnosticConsumer DiagPrinter; - Diags.addConsumer(DiagPrinter); +void anchorForGetMainExecutable() {} - std::vector, - syntax::AbsolutePosition>> Tokens; - if (getTokensFromFile(InputFilename, LangOpts, SourceMgr, - Diags, Tokens) == EXIT_FAILURE) { - return EXIT_FAILURE; - } - - for (auto TokAndPos : Tokens) { - TokAndPos.first->print(llvm::outs()); - } - - return Diags.hadAnyError() ? EXIT_FAILURE : EXIT_SUCCESS; -} - -int doDumpTokenSyntax(const StringRef InputFilename) { - LangOptions LangOpts; - SourceManager SourceMgr; - DiagnosticEngine Diags(SourceMgr); - PrintingDiagnosticConsumer DiagPrinter; - Diags.addConsumer(DiagPrinter); - - - std::vector, - syntax::AbsolutePosition>> Tokens; - if (getTokensFromFile(InputFilename, LangOpts, SourceMgr, - Diags, Tokens) == EXIT_FAILURE) { - return EXIT_FAILURE; - } - - for (auto TokAndPos : Tokens) { - TokAndPos.second.printLineAndColumn(llvm::outs()); - llvm::outs() << "\n"; - TokAndPos.first->dump(llvm::outs()); - llvm::outs() << "\n"; - } - - return Diags.hadAnyError() ? EXIT_FAILURE : EXIT_SUCCESS; -} - -int doFullParseRoundTrip(const StringRef InputFilename) { +int getSyntaxTree(const char *MainExecutablePath, + const StringRef InputFilename, + CompilerInstance &Instance, + llvm::SmallVectorImpl &TopLevelDecls, + std::vector, + syntax::AbsolutePosition>> &Tokens) { CompilerInvocation Invocation; Invocation.addInputFilename(InputFilename); + + Invocation.setMainExecutablePath( + llvm::sys::fs::getMainExecutable(MainExecutablePath, + reinterpret_cast(&anchorForGetMainExecutable))); + Invocation.setModuleName("Test"); - CompilerInstance Instance; auto &SourceMgr = Instance.getSourceMgr(); @@ -172,8 +143,6 @@ int doFullParseRoundTrip(const StringRef InputFilename) { assert(SF && "No source file"); // Retokenize the buffer with full fidelity - std::vector, - syntax::AbsolutePosition>> Tokens; if (getTokensFromFile(BufferID, Invocation.getLangOptions(), SourceMgr, Instance.getDiags(), Tokens) == EXIT_FAILURE) { @@ -192,11 +161,73 @@ int doFullParseRoundTrip(const StringRef InputFilename) { auto NewNode = transformAST(ASTNode(Decl), Sema, SourceMgr, BufferID, Tokens); if (NewNode.hasValue()) { - NewNode.getValue().print(llvm::outs()); - auto Symbol = Sema.getNodeForSyntax(NewNode.getValue()); + TopLevelDecls.push_back(NewNode.getValue()); } } + return EXIT_SUCCESS; +} + +int doFullLexRoundTrip(const StringRef InputFilename) { + LangOptions LangOpts; + SourceManager SourceMgr; + DiagnosticEngine Diags(SourceMgr); + PrintingDiagnosticConsumer DiagPrinter; + Diags.addConsumer(DiagPrinter); + + std::vector, + syntax::AbsolutePosition>> Tokens; + if (getTokensFromFile(InputFilename, LangOpts, SourceMgr, + Diags, Tokens) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + + for (auto TokAndPos : Tokens) { + TokAndPos.first->print(llvm::outs()); + } + + return Diags.hadAnyError() ? EXIT_FAILURE : EXIT_SUCCESS; +} + +int doDumpRawTokenSyntax(const StringRef InputFilename) { + LangOptions LangOpts; + SourceManager SourceMgr; + DiagnosticEngine Diags(SourceMgr); + PrintingDiagnosticConsumer DiagPrinter; + Diags.addConsumer(DiagPrinter); + + std::vector, + syntax::AbsolutePosition>> Tokens; + if (getTokensFromFile(InputFilename, LangOpts, SourceMgr, + Diags, Tokens) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + + for (auto TokAndPos : Tokens) { + TokAndPos.second.printLineAndColumn(llvm::outs()); + llvm::outs() << "\n"; + TokAndPos.first->dump(llvm::outs()); + llvm::outs() << "\n"; + } + + return Diags.hadAnyError() ? EXIT_FAILURE : EXIT_SUCCESS; +} + +int doFullParseRoundTrip(const char *MainExecutablePath, + const StringRef InputFilename) { + + llvm::SmallVector TopLevelDecls; + std::vector, + syntax::AbsolutePosition>> Tokens; + CompilerInstance Instance; + + getSyntaxTree(MainExecutablePath, InputFilename, Instance, + TopLevelDecls, Tokens); + + for (auto &Node : TopLevelDecls) { + Node.print(llvm::outs()); + } + if (Tokens.back().first->getTokenKind() == tok::eof) { Tokens.back().first->print(llvm::outs()); } @@ -204,6 +235,30 @@ int doFullParseRoundTrip(const StringRef InputFilename) { return EXIT_SUCCESS; } +int doSerializeRawTree(const char *MainExecutablePath, + const StringRef InputFilename) { + + llvm::SmallVector TopLevelDecls; + std::vector, + syntax::AbsolutePosition>> Tokens; + CompilerInstance Instance; + + getSyntaxTree(MainExecutablePath, InputFilename, Instance, + TopLevelDecls, Tokens); + + std::vector> RawTopLevelDecls; + for (auto &Decl : TopLevelDecls) { + RawTopLevelDecls.push_back(Decl.getRaw()); + } + + swift::json::Output out(llvm::outs()); + out << RawTopLevelDecls; + + llvm::outs() << "\n"; + + return EXIT_SUCCESS; +} + int main(int argc, char *argv[]) { llvm::cl::ParseCommandLineOptions(argc, argv, "Swift Syntax Test\n"); @@ -220,14 +275,17 @@ int main(int argc, char *argv[]) { } switch (options::Action) { - case ActionType::DumpTokenSyntax: - ExitCode = doDumpTokenSyntax(options::InputSourceFilename); + case ActionType::DumpRawTokenSyntax: + ExitCode = doDumpRawTokenSyntax(options::InputSourceFilename); break; case ActionType::FullLexRoundTrip: ExitCode = doFullLexRoundTrip(options::InputSourceFilename); break; case ActionType::FullParseRoundTrip: - ExitCode = doFullParseRoundTrip(options::InputSourceFilename); + ExitCode = doFullParseRoundTrip(argv[0], options::InputSourceFilename); + break; + case ActionType::SerializeRawTree: + ExitCode = doSerializeRawTree(argv[0], options::InputSourceFilename); break; case ActionType::None: llvm::errs() << "an action is required\n"; diff --git a/unittests/SourceKit/SwiftLang/CMakeLists.txt b/unittests/SourceKit/SwiftLang/CMakeLists.txt index 27dd36fc6b6..fc89375ecce 100644 --- a/unittests/SourceKit/SwiftLang/CMakeLists.txt +++ b/unittests/SourceKit/SwiftLang/CMakeLists.txt @@ -2,6 +2,7 @@ if(NOT SWIFT_HOST_VARIANT MATCHES "${SWIFT_DARWIN_EMBEDDED_VARIANTS}") add_swift_unittest(SourceKitSwiftLangTests CursorInfoTest.cpp + EditingTest.cpp ) target_link_libraries(SourceKitSwiftLangTests diff --git a/unittests/SourceKit/SwiftLang/EditingTest.cpp b/unittests/SourceKit/SwiftLang/EditingTest.cpp new file mode 100644 index 00000000000..fb707414b8a --- /dev/null +++ b/unittests/SourceKit/SwiftLang/EditingTest.cpp @@ -0,0 +1,224 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "SourceKit/Core/Context.h" +#include "SourceKit/Core/LangSupport.h" +#include "SourceKit/Core/NotificationCenter.h" +#include "SourceKit/Support/Concurrency.h" +#include "SourceKit/SwiftLang/Factory.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/TargetSelect.h" +#include "gtest/gtest.h" +#include +#include + +using namespace SourceKit; +using namespace llvm; + +static StringRef getRuntimeLibPath() { + return sys::path::parent_path(SWIFTLIB_DIR); +} + +namespace { + +class DiagConsumer : public EditorConsumer { +public: + UIdent DiagStage; + std::vector Diags; + +private: + void handleRequestError(const char *Description) override { + llvm_unreachable("unexpected error"); + } + + bool handleSyntaxMap(unsigned Offset, unsigned Length, UIdent Kind) override { + return false; + } + + bool handleSemanticAnnotation(unsigned Offset, unsigned Length, + UIdent Kind, bool isSystem) override { + return false; + } + + bool beginDocumentSubStructure(unsigned Offset, unsigned Length, + UIdent Kind, UIdent AccessLevel, + UIdent SetterAccessLevel, + unsigned NameOffset, + unsigned NameLength, + unsigned BodyOffset, + unsigned BodyLength, + StringRef DisplayName, + StringRef TypeName, + StringRef RuntimeName, + StringRef SelectorName, + ArrayRef InheritedTypes, + ArrayRef Attrs) override { + return false; + } + + bool endDocumentSubStructure() override { return false; } + + bool handleDocumentSubStructureElement(UIdent Kind, + unsigned Offset, + unsigned Length) override { + return false; + } + + bool recordAffectedRange(unsigned Offset, unsigned Length) override { + return false; + } + + bool recordAffectedLineRange(unsigned Line, unsigned Length) override { + return false; + } + + bool recordFormattedText(StringRef Text) override { return false; } + + bool setDiagnosticStage(UIdent diagStage) override { + DiagStage = diagStage; + return true; + } + bool handleDiagnostic(const DiagnosticEntryInfo &Info, + UIdent DiagStage) override { + Diags.push_back(Info); + return true; + } + + bool handleSourceText(StringRef Text) override { return false; } +}; + +struct DocUpdateMutexState { + std::mutex Mtx; + std::condition_variable CV; + bool HasUpdate = false; +}; + +class EditTest : public ::testing::Test { + SourceKit::Context *Ctx; + std::shared_ptr DocUpdState; + +public: + EditTest() { + // This is avoiding destroying \p SourceKit::Context because another + // thread may be active trying to use it to post notifications. + // FIXME: Use shared_ptr ownership to avoid such issues. + Ctx = new SourceKit::Context(getRuntimeLibPath(), + SourceKit::createSwiftLangSupport, + /*dispatchOnMain=*/false); + auto localDocUpdState = std::make_shared(); + Ctx->getNotificationCenter().addDocumentUpdateNotificationReceiver( + [localDocUpdState](StringRef docName) { + std::unique_lock lk(localDocUpdState->Mtx); + localDocUpdState->HasUpdate = true; + localDocUpdState->CV.notify_one(); + }); + DocUpdState = localDocUpdState; + } + + LangSupport &getLang() { return Ctx->getSwiftLangSupport(); } + + void SetUp() override { + llvm::InitializeAllTargets(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmPrinters(); + llvm::InitializeAllAsmParsers(); + } + + void addNotificationReceiver(DocumentUpdateNotificationReceiver Receiver) { + Ctx->getNotificationCenter().addDocumentUpdateNotificationReceiver(Receiver); + } + + bool waitForDocUpdate() { + std::chrono::seconds secondsToWait(10); + std::unique_lock lk(DocUpdState->Mtx); + auto when = std::chrono::system_clock::now() + secondsToWait; + return !DocUpdState->CV.wait_until( + lk, when, [&]() { return DocUpdState->HasUpdate; }); + } + + void open(const char *DocName, StringRef Text, ArrayRef CArgs, + EditorConsumer &Consumer) { + auto Args = makeArgs(DocName, CArgs); + auto Buf = MemoryBuffer::getMemBufferCopy(Text, DocName); + getLang().editorOpen(DocName, Buf.get(), /*EnableSyntaxMap=*/false, Consumer, + Args); + } + + void replaceText(StringRef DocName, unsigned Offset, unsigned Length, + StringRef Text, EditorConsumer &Consumer) { + auto Buf = MemoryBuffer::getMemBufferCopy(Text, DocName); + getLang().editorReplaceText(DocName, Buf.get(), Offset, Length, Consumer); + } + + unsigned findOffset(StringRef Val, StringRef Text) { + auto pos = Text.find(Val); + assert(pos != StringRef::npos); + return pos; + } + + void reset(DiagConsumer &Consumer) { + Consumer.Diags.clear(); + Consumer.DiagStage = UIdent(); + std::unique_lock lk(DocUpdState->Mtx); + DocUpdState->HasUpdate = false; + } + +private: + std::vector makeArgs(const char *DocName, + ArrayRef CArgs) { + std::vector Args = CArgs; + Args.push_back(DocName); + return Args; + } +}; + +} // anonymous namespace + +static UIdent SemaDiagStage("source.diagnostic.stage.swift.sema"); +static UIdent ParseDiagStage("source.diagnostic.stage.swift.parse"); + +TEST_F(EditTest, DiagsAfterEdit) { + const char *DocName = "/test.swift"; + const char *Contents = + "func foo\n" + "let v = 0\n"; + const char *Args[] = { "-parse-as-library" }; + + DiagConsumer Consumer; + open(DocName, Contents, Args, Consumer); + ASSERT_TRUE(Consumer.Diags.size() == 1); + EXPECT_STREQ("expected '(' in argument list of function declaration", Consumer.Diags[0].Description.c_str()); + + reset(Consumer); + replaceText(DocName, findOffset("func foo", Contents)+strlen("func foo"), 0, "(){}", Consumer); + EXPECT_TRUE(Consumer.Diags.empty()); + + bool expired = waitForDocUpdate(); + ASSERT_FALSE(expired); + + reset(Consumer); + replaceText(DocName, 0, 0, StringRef(), Consumer); + EXPECT_TRUE(Consumer.Diags.empty()); + + // If typecheck completed for the edit we'll get 'sema stage', otherwise + // we'll get 'parser stage' and there will be another doc-update. + if (Consumer.DiagStage == ParseDiagStage) { + bool expired = waitForDocUpdate(); + ASSERT_FALSE(expired); + + reset(Consumer); + replaceText(DocName, 0, 0, StringRef(), Consumer); + EXPECT_TRUE(Consumer.Diags.empty()); + } + EXPECT_EQ(SemaDiagStage, Consumer.DiagStage); +} diff --git a/unittests/Syntax/DeclSyntaxTests.cpp b/unittests/Syntax/DeclSyntaxTests.cpp index 87f3e7d68b5..acc5f42ecd9 100644 --- a/unittests/Syntax/DeclSyntaxTests.cpp +++ b/unittests/Syntax/DeclSyntaxTests.cpp @@ -43,10 +43,10 @@ TEST(DeclSyntaxTests, DeclModifierGetAPIs) { auto RParen = SyntaxFactory::makeRightParenToken({}, {}); auto Mod = SyntaxFactory::makeDeclModifier(Private, LParen, Set, RParen); - ASSERT_EQ(Private, Mod.getName()); - ASSERT_EQ(LParen, Mod.getLeftParenToken()); - ASSERT_EQ(Set, Mod.getArgument()); - ASSERT_EQ(RParen, Mod.getRightParenToken()); + ASSERT_EQ(Private.getRaw(), Mod.getName().getRaw()); + ASSERT_EQ(LParen.getRaw(), Mod.getLeftParenToken().getRaw()); + ASSERT_EQ(Set.getRaw(), Mod.getArgument().getRaw()); + ASSERT_EQ(RParen.getRaw(), Mod.getRightParenToken().getRaw()); } TEST(DeclSyntaxTests, DeclModifierWithAPIs) { @@ -252,21 +252,21 @@ TEST(DeclSyntaxTests, FunctionParameterGetAPIs) { Colon, Int, NoEllipsis, Equal, One, Comma); - ASSERT_EQ(ExternalName, Param.getExternalName()); - ASSERT_EQ(LocalName, Param.getLocalName()); - ASSERT_EQ(Colon, Param.getColonToken()); + ASSERT_EQ(ExternalName.getRaw(), Param.getExternalName().getRaw()); + ASSERT_EQ(LocalName.getRaw(), Param.getLocalName().getRaw()); + ASSERT_EQ(Colon.getRaw(), Param.getColonToken().getRaw()); auto GottenType = Param.getTypeSyntax().getValue(); auto GottenType2 = Param.getTypeSyntax().getValue(); ASSERT_TRUE(GottenType.hasSameIdentityAs(GottenType2)); - ASSERT_EQ(Equal, Param.getEqualToken()); + ASSERT_EQ(Equal.getRaw(), Param.getEqualToken().getRaw()); auto GottenDefaultValue = Param.getDefaultValue().getValue(); auto GottenDefaultValue2 = Param.getDefaultValue().getValue(); ASSERT_TRUE(GottenDefaultValue.hasSameIdentityAs(GottenDefaultValue2)); - ASSERT_EQ(Comma, Param.getTrailingComma()); + ASSERT_EQ(Comma.getRaw(), Param.getTrailingComma().getRaw()); // Test that llvm::None is returned for non-token missing children: auto Decimated = Param @@ -392,7 +392,7 @@ TEST(DeclSyntaxTests, FunctionSignatureGetAPIs) { auto Sig = SyntaxFactory::makeFunctionSignature(LParen, List, RParen, Throws, Arrow, NoAttributes, Int); - ASSERT_EQ(LParen, Sig.getLeftParenToken()); + ASSERT_EQ(LParen.getRaw(), Sig.getLeftParenToken().getRaw()); { SmallString<48> Scratch; @@ -407,10 +407,10 @@ TEST(DeclSyntaxTests, FunctionSignatureGetAPIs) { "with radius: Int = -1, "); } - ASSERT_EQ(RParen, Sig.getRightParenToken()); - ASSERT_EQ(Throws, Sig.getThrowsToken()); - ASSERT_TRUE(Sig.getRethrowsToken()->isMissing()); - ASSERT_EQ(Arrow, Sig.getArrowToken()); + ASSERT_EQ(RParen.getRaw(), Sig.getRightParenToken().getRaw()); + ASSERT_EQ(Throws.getRaw(), Sig.getThrowsToken().getRaw()); + ASSERT_TRUE(Sig.getRethrowsToken().isMissing()); + ASSERT_EQ(Arrow.getRaw(), Sig.getArrowToken().getRaw()); { SmallString<48> Scratch; diff --git a/unittests/Syntax/ExprSyntaxTests.cpp b/unittests/Syntax/ExprSyntaxTests.cpp index 78444d0c7df..baf36f9c50b 100644 --- a/unittests/Syntax/ExprSyntaxTests.cpp +++ b/unittests/Syntax/ExprSyntaxTests.cpp @@ -72,7 +72,7 @@ TEST(ExprSyntaxTests, SymbolicReferenceExprGetAPIs) { auto Ref = SyntaxFactory::makeSymbolicReferenceExpr(Array, GenericArgs); - ASSERT_EQ(Ref.getIdentifier(), Array); + ASSERT_EQ(Ref.getIdentifier().getRaw(), Array.getRaw()); auto GottenArgs = Ref.getGenericArgumentClause().getValue(); auto GottenArgs2 = Ref.getGenericArgumentClause().getValue(); @@ -172,8 +172,8 @@ TEST(ExprSyntaxTests, FunctionCallArgumentGetAPIs) { auto Arg = SyntaxFactory::makeFunctionCallArgument(X, Colon, SymbolicRef, Comma); - ASSERT_EQ(X, Arg.getLabel()); - ASSERT_EQ(Colon, Arg.getColonToken()); + ASSERT_EQ(X.getRaw(), Arg.getLabel().getRaw()); + ASSERT_EQ(Colon.getRaw(), Arg.getColonToken().getRaw()); auto GottenExpr = Arg.getExpression().getValue(); auto GottenExpr2 = Arg.getExpression().getValue(); @@ -183,7 +183,7 @@ TEST(ExprSyntaxTests, FunctionCallArgumentGetAPIs) { GottenExpr.print(OS); ASSERT_EQ("foo", OS.str().str()); - ASSERT_EQ(Comma, Arg.getTrailingComma()); + ASSERT_EQ(Comma.getRaw(), Arg.getTrailingComma().getRaw()); } } @@ -407,8 +407,8 @@ TEST(ExprSyntaxTests, FunctionCallExprGetAPIs) { ASSERT_EQ(OS.str().str(), "foo"); } - ASSERT_EQ(LeftParen, Call.getLeftParen()); - ASSERT_EQ(RightParen, Call.getRightParen()); + ASSERT_EQ(LeftParen.getRaw(), Call.getLeftParen().getRaw()); + ASSERT_EQ(RightParen.getRaw(), Call.getRightParen().getRaw()); { auto GottenArgs1 = Call.getArgumentList(); diff --git a/unittests/Syntax/StmtSyntaxTests.cpp b/unittests/Syntax/StmtSyntaxTests.cpp index f07cb225b4f..2dc67cca77d 100644 --- a/unittests/Syntax/StmtSyntaxTests.cpp +++ b/unittests/Syntax/StmtSyntaxTests.cpp @@ -19,7 +19,8 @@ TEST(StmtSyntaxTests, FallthroughStmtGetAPIs) { .withFallthroughKeyword(FallthroughKW); /// This should be directly shared through reference-counting. - ASSERT_EQ(FallthroughKW, Fallthrough.getFallthroughKeyword()); + ASSERT_EQ(FallthroughKW.getRaw(), Fallthrough.getFallthroughKeyword() + .getRaw()); } TEST(StmtSyntaxTests, FallthroughStmtWithAPIs) { @@ -50,9 +51,9 @@ TEST(StmtSyntaxTests, FallthroughStmtMakeAPIs) { llvm::SmallString<48> Scratch; llvm::raw_svector_ostream OS(Scratch); - FallthroughKW = FallthroughKW->withLeadingTrivia(Trivia::spaces(2)); + auto NewFallthroughKW = FallthroughKW.withLeadingTrivia(Trivia::spaces(2)); - SyntaxFactory::makeFallthroughStmt(FallthroughKW).print(OS); + SyntaxFactory::makeFallthroughStmt(NewFallthroughKW).print(OS); ASSERT_EQ(OS.str().str(), " fallthrough"); } @@ -60,9 +61,10 @@ TEST(StmtSyntaxTests, FallthroughStmtMakeAPIs) { llvm::SmallString<48> Scratch; llvm::raw_svector_ostream OS(Scratch); - FallthroughKW = FallthroughKW->withTrailingTrivia(Trivia::spaces(2)); + auto NewFallthroughKW = FallthroughKW.withLeadingTrivia(Trivia::spaces(2)) + .withTrailingTrivia(Trivia::spaces(2)); - SyntaxFactory::makeFallthroughStmt(FallthroughKW).print(OS); + SyntaxFactory::makeFallthroughStmt(NewFallthroughKW).print(OS); ASSERT_EQ(OS.str().str(), " fallthrough "); } @@ -83,8 +85,8 @@ TEST(StmtSyntaxTests, BreakStmtGetAPIs) { auto Break = SyntaxFactory::makeBreakStmt(BreakKW, Label); /// These should be directly shared through reference-counting. - ASSERT_EQ(BreakKW, Break.getBreakKeyword()); - ASSERT_EQ(Label, Break.getLabel()); + ASSERT_EQ(BreakKW.getRaw(), Break.getBreakKeyword().getRaw()); + ASSERT_EQ(Label.getRaw(), Break.getLabel().getRaw()); } TEST(StmtSyntaxTests, BreakStmtWithAPIs) { @@ -115,7 +117,7 @@ TEST(StmtSyntaxTests, BreakStmtWithAPIs) { { llvm::SmallString<48> Scratch; llvm::raw_svector_ostream OS(Scratch); - Break.withBreakKeyword(BreakKW->withTrailingTrivia(Trivia::spaces(1))) + Break.withBreakKeyword(BreakKW.withTrailingTrivia(Trivia::spaces(1))) .withLabel(Label) .print(OS); ASSERT_EQ(OS.str().str(), "break theRules"); // sometimes @@ -148,8 +150,8 @@ TEST(StmtSyntaxTests, ContinueStmtGetAPIs) { auto Continue = SyntaxFactory::makeContinueStmt(ContinueKW, Label); /// These should be directly shared through reference-counting. - ASSERT_EQ(ContinueKW, Continue.getContinueKeyword()); - ASSERT_EQ(Label, Continue.getLabel()); + ASSERT_EQ(ContinueKW.getRaw(), Continue.getContinueKeyword().getRaw()); + ASSERT_EQ(Label.getRaw(), Continue.getLabel().getRaw()); } TEST(StmtSyntaxTests, ContinueStmtWithAPIs) { @@ -180,7 +182,7 @@ TEST(StmtSyntaxTests, ContinueStmtWithAPIs) { llvm::SmallString<48> Scratch; llvm::raw_svector_ostream OS(Scratch); Continue - .withContinueKeyword(ContinueKW->withTrailingTrivia(Trivia::spaces(1))) + .withContinueKeyword(ContinueKW.withTrailingTrivia(Trivia::spaces(1))) .withLabel(Label) .print(OS); ASSERT_EQ(OS.str().str(), "continue toCare"); // for each other @@ -235,7 +237,7 @@ TEST(StmtSyntaxTests, ReturnStmtGetAPIs) { auto MinusOne = SyntaxFactory::makeIntegerLiteralExpr(Minus, OneDigits); auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, MinusOne); - ASSERT_EQ(ReturnKW, Return.getReturnKeyword()); + ASSERT_EQ(ReturnKW.getRaw(), Return.getReturnKeyword().getRaw()); auto GottenExpression = Return.getExpression().getValue(); auto GottenExpression2 = Return.getExpression().getValue(); ASSERT_TRUE(GottenExpression.hasSameIdentityAs(GottenExpression2)); diff --git a/unittests/Syntax/SyntaxCollectionTests.cpp b/unittests/Syntax/SyntaxCollectionTests.cpp index 656c44dfe1f..f269957e5d3 100644 --- a/unittests/Syntax/SyntaxCollectionTests.cpp +++ b/unittests/Syntax/SyntaxCollectionTests.cpp @@ -15,7 +15,7 @@ FunctionCallArgumentSyntax getCannedArgument() { auto Colon = SyntaxFactory::makeColonToken({}, Trivia::spaces(1)); auto SymbolicRef = SyntaxFactory::makeSymbolicReferenceExpr(Foo, llvm::None); auto Comma = SyntaxFactory::makeCommaToken({}, Trivia::spaces(1)); - auto NoComma = TokenSyntax::missingToken(tok::comma, ","); + auto NoComma = RawTokenSyntax::missingToken(tok::comma, ","); return SyntaxFactory::makeFunctionCallArgument(X, Colon, SymbolicRef, Comma); } diff --git a/unittests/Syntax/UnknownSyntaxTests.cpp b/unittests/Syntax/UnknownSyntaxTests.cpp index 9173e51f431..7f33b8edf77 100644 --- a/unittests/Syntax/UnknownSyntaxTests.cpp +++ b/unittests/Syntax/UnknownSyntaxTests.cpp @@ -55,12 +55,7 @@ TEST(UnknownSyntaxTests, UnknownSyntaxMakeAPIs) { // Wrap that symbolic reference as an UnknownSyntax. This has the same // RawSyntax layout but with the Unknown Kind. - auto UnknownSymbolicRefData = UnknownSyntaxData::make(SymbolicRef.getRaw()); - - auto Unknown = UnknownSyntax { - UnknownSymbolicRefData, - UnknownSymbolicRefData.get() - }; + auto Unknown = make(SymbolicRef.getRaw()); // Print the unknown syntax. It should also print as "Array". SmallString<48> UnknownScratch; @@ -84,13 +79,8 @@ TEST(UnknownSyntaxTests, UnknownSyntaxGetAPIs) { GottenExpr.print(KnownOS); // Wrap that call as an UnknownExprSyntax. This has the same - // RawSyntax layout but with the UnknownExpr Kind. - auto UnknownCallData = UnknownExprSyntaxData::make(Call.getRaw()); - - auto Unknown = UnknownExprSyntax { - UnknownCallData, - UnknownCallData.get() - }; + // RawSyntax layout but with the UnknownExpr Kind.; + auto Unknown = make(Call.getRaw()); ASSERT_EQ(Unknown.getNumChildren(), size_t(2)); @@ -120,12 +110,7 @@ TEST(UnknownSyntaxTests, UnknownSyntaxGetAPIs) { // Wrap that symbolic reference as an UnknownSyntax. This has the same // RawSyntax layout but with the Unknown Kind. - auto UnknownCallData = UnknownSyntaxData::make(Call.getRaw()); - - auto Unknown = UnknownSyntax { - UnknownCallData, - UnknownCallData.get() - }; + auto Unknown = make(Call.getRaw()); ASSERT_EQ(Unknown.getNumChildren(), size_t(2)); @@ -162,13 +147,8 @@ TEST(UnknownSyntaxTests, EmbedUnknownExpr) { // Let's make a function call expression where the called expression is // actually unknown. It should print the same and have the same structure // as one with a known called expression. - auto UnknownSymbolicRefData = - UnknownExprSyntaxData::make(SymbolicRef.getRaw()); - - auto UnknownSymbolicRef = UnknownExprSyntax { - UnknownSymbolicRefData, - UnknownSymbolicRefData.get() - }.castTo(); + auto UnknownSymbolicRef = make(SymbolicRef.getRaw()) + .castTo(); SmallString<48> UnknownScratch; llvm::raw_svector_ostream UnknownOS(UnknownScratch); diff --git a/unittests/runtime/Exclusivity.cpp b/unittests/runtime/Exclusivity.cpp index ab0e87463a1..35a34feb9d7 100644 --- a/unittests/runtime/Exclusivity.cpp +++ b/unittests/runtime/Exclusivity.cpp @@ -16,7 +16,7 @@ using namespace swift; -TEST(TextExclusivity, testNullPC) { +TEST(TestExclusivity, testNullPC) { ValueBuffer scratch, scratch2; long var; swift_beginAccess(&var, &scratch, @@ -29,7 +29,7 @@ TEST(TextExclusivity, testNullPC) { swift_endAccess(&scratch); } -TEST(TextExclusivity, testPCOne) { +TEST(TestExclusivity, testPCOne) { ValueBuffer scratch, scratch2; long var; swift_beginAccess(&var, &scratch, @@ -42,7 +42,7 @@ TEST(TextExclusivity, testPCOne) { swift_endAccess(&scratch); } -TEST(TextExclusivity, testBogusPC) { +TEST(TestExclusivity, testBogusPC) { ValueBuffer scratch, scratch2; long var; swift_beginAccess(&var, &scratch, @@ -54,3 +54,34 @@ TEST(TextExclusivity, testBogusPC) { swift_endAccess(&scratch2); swift_endAccess(&scratch); } + +// rdar://32866493 +TEST(TestExclusivity, testNonNested) { + const int N = 5; + ValueBuffer scratches[N]; + long vars[N]; + + auto begin = [&](unsigned i) { + assert(i < N); + swift_beginAccess(&vars[i], &scratches[i], ExclusivityFlags::Modify, 0); + }; + auto end = [&](unsigned i) { + assert(i < N); + swift_endAccess(&scratches[i]); + memset(&scratches[i], /*gibberish*/ 0x99, sizeof(ValueBuffer)); + }; + auto accessAll = [&] { + for (unsigned i = 0; i != N; ++i) begin(i); + for (unsigned i = 0; i != N; ++i) end(i); + }; + + accessAll(); + begin(0); begin(1); end(0); end(1); + begin(0); begin(1); end(0); end(1); + accessAll(); + begin(1); begin(0); begin(2); end(0); end(2); end(1); + accessAll(); + begin(0); begin(1); begin(2); begin(3); begin(4); + end(1); end(4); end(0); end(2); end(3); + accessAll(); +} diff --git a/unittests/runtime/Metadata.cpp b/unittests/runtime/Metadata.cpp index d85d052ae04..9e3a8c5b56d 100644 --- a/unittests/runtime/Metadata.cpp +++ b/unittests/runtime/Metadata.cpp @@ -839,9 +839,6 @@ TEST(MetadataTest, getExistentialTypeMetadata_subclass) { }); } -static const void *AllocatedBuffer = nullptr; -static const void *DeallocatedBuffer = nullptr; - namespace swift { void installCommonValueWitnesses(ValueWitnessTable *vwtable); } // namespace swift diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 3ac8253bed7..cca771d4ca9 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -898,6 +898,18 @@ build-subdir=buildbot_incremental_asan enable-asan +[preset: buildbot_incremental_linux,lsan] +build-subdir=buildbot_incremental_lsan + +release-debuginfo +assertions +enable-lsan + +dash-dash + +build-ninja +reconfigure + #===------------------------------------------------------------------------===# # OS X Package Builders #===------------------------------------------------------------------------===# diff --git a/utils/build-script b/utils/build-script index 8aa4dc39fb9..e945eeacff7 100755 --- a/utils/build-script +++ b/utils/build-script @@ -147,6 +147,11 @@ class HostSpecificConfiguration(object): test = False name = deployment_target.name + + for skip_test_arch in invocation.platforms_archs_to_skip_test: + if deployment_target.name == skip_test_arch.name: + test = False + if build: # Validation and long tests require building the full standard # library, whereas the other targets can build a slightly @@ -499,6 +504,7 @@ class BuildScriptInvocation(object): self.platforms_to_skip_build.add(StdlibDeploymentTarget.Android) self.platforms_to_skip_test = set() + self.platforms_archs_to_skip_test = set() if args.skip_test_linux: self.platforms_to_skip_test.add(StdlibDeploymentTarget.Linux) if args.skip_test_freebsd: @@ -515,6 +521,9 @@ class BuildScriptInvocation(object): if args.skip_test_ios_simulator: self.platforms_to_skip_test.add( StdlibDeploymentTarget.iOSSimulator) + if args.skip_test_ios_32bit_simulator: + self.platforms_archs_to_skip_test.add( + StdlibDeploymentTarget.iOSSimulator.i386) if args.skip_test_tvos_host: self.platforms_to_skip_test.add(StdlibDeploymentTarget.AppleTV) else: @@ -682,6 +691,14 @@ class BuildScriptInvocation(object): # NOT pass them to build-script-impl. if args.enable_asan: impl_args += ["--enable-asan"] + # If we have lsan, we need to export our suppression list. The actual + # passing in of the LSAN flag is done via the normal cmake method. We + # do not pass the flag to build-script-impl. + if args.enable_lsan: + supp_file = os.path.join(SWIFT_SOURCE_ROOT, SWIFT_REPO_NAME, + "utils", + "lsan_leaks_suppression_list.txt") + os.environ['LSAN_OPTIONS'] = 'suppressions={}'.format(supp_file) if args.verbose_build: impl_args += ["--verbose-build"] if args.install_symroot: @@ -772,6 +789,8 @@ class BuildScriptInvocation(object): impl_args += ["--skip-test-ios-host"] if args.skip_test_ios_simulator: impl_args += ["--skip-test-ios-simulator"] + if args.skip_test_ios_32bit_simulator: + impl_args += ["--skip-test-ios-32bit-simulator"] if args.skip_test_tvos_host: impl_args += ["--skip-test-tvos-host"] if args.skip_test_tvos_simulator: @@ -1780,6 +1799,11 @@ iterations with -O", "--skip-test-ios-simulator", help="skip testing iOS simulator targets", action=arguments.action.optional_bool) + skip_test_group.add_argument( + "--skip-test-ios-32bit-simulator", + help="skip testing iOS 32 bit simulator targets", + action=arguments.action.optional_bool, + default=True) skip_test_group.add_argument( "--skip-test-ios-host", help="skip testing iOS device targets on the host machine (the phone " @@ -2018,6 +2042,10 @@ iterations with -O", parser.add_argument( "--enable-tsan-runtime", help="enable Thread Sanitizer on the swift runtime") + parser.add_argument( + "--enable-lsan", + help="enable Leak Sanitizer for swift tools", + action=arguments.action.optional_bool) parser.add_argument( "--compiler-vendor", diff --git a/utils/build-script-impl b/utils/build-script-impl index d08bba0693a..830381cef79 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -142,6 +142,7 @@ KNOWN_SETTINGS=( skip-test-freebsd "" "set to skip testing Swift stdlibs for FreeBSD" skip-test-cygwin "" "set to skip testing Swift stdlibs for Cygwin" skip-test-osx "" "set to skip testing Swift stdlibs for OS X" + skip-test-ios-32bit-simulator "" "set to skip testing Swift stdlibs for iOS 32bit simulators" skip-test-ios-simulator "" "set to skip testing Swift stdlibs for iOS simulators (i.e. test devices only)" skip-test-ios-host "" "set to skip testing the host parts of the iOS toolchain" skip-test-tvos-simulator "" "set to skip testing Swift stdlibs for tvOS simulators (i.e. test devices only)" @@ -1355,11 +1356,19 @@ function calculate_targets_for_host() { build_benchmark_this_target= fi ;; - iphonesimulator-*) + iphonesimulator-x86_64) swift_sdk="IOS_SIMULATOR" build_for_this_target=$(not ${SKIP_BUILD_IOS_SIMULATOR}) test_this_target=$(not ${SKIP_TEST_IOS_SIMULATOR}) ;; + iphonesimulator-i386) + swift_sdk="IOS_SIMULATOR" + build_for_this_target=$(not ${SKIP_BUILD_IOS_SIMULATOR}) + if [[ "${SKIP_TEST_IOS_SIMULATOR}" == "1" ]] ; then + SKIP_TEST_IOS_32BIT_SIMULATOR="${SKIP_TEST_IOS_SIMULATOR}" + fi + test_this_target=$(not ${SKIP_TEST_IOS_32BIT_SIMULATOR}) + ;; appletvos-*) swift_sdk="TVOS" build_for_this_target=$(not ${SKIP_BUILD_TVOS_DEVICE}) @@ -1439,6 +1448,7 @@ function calculate_targets_for_host() { test_subset_target_suffix="-only_long" fi fi + SWIFT_TEST_TARGETS+=("check-swift${test_subset_target_suffix}${test_target_suffix}-${stdlib_deployment_target}") if [[ $(not ${SKIP_TEST_OPTIMIZED}) && ! -n "${test_host_only}" ]] ; then SWIFT_TEST_TARGETS+=("check-swift${test_subset_target_suffix}-optimize-${stdlib_deployment_target}") @@ -3201,7 +3211,7 @@ for host in "${ALL_HOSTS[@]}"; do # Copy executables and shared libraries from the `host_install_destdir` to # INSTALL_SYMROOT and run dsymutil on them. (cd "${host_install_destdir}" && - find ./"${TOOLCHAIN_PREFIX}" -perm -0111 -type f -print | cpio -pdm "${INSTALL_SYMROOT}") + find ./"${TOOLCHAIN_PREFIX}" -perm -0111 -type f -print | cpio --insecure -pdm "${INSTALL_SYMROOT}") # Run dsymutil on executables and shared libraries. # diff --git a/utils/chex.py b/utils/chex.py new file mode 100755 index 00000000000..e84b1fa10e5 --- /dev/null +++ b/utils/chex.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# Check HEX -- a stupid filter that allows hexadecimal literals to be checked +# for in LLVM IR FileCheck tests. It works by replacing occurrences of +# strings matching the regex /< (i[0-9]+) \s+ (0x[0-9A-Fa-f]+) >/x with the +# decimal literal equivalent that would really appear in printed LLVM IR. + +from __future__ import print_function + +import re +import sys + +hex = re.compile(r"""<(i([0-9]+)\s+)0x([0-9A-Fa-f_]+)>""") + + +def hexReplace(match): + # Integer type is match group 1 + ty = match.group(1) + # Integer bit width is match group 2 + bits = int(match.group(2)) + # Hex value is match group 3 + value = int(match.group(3).replace("_", ""), base=16) + # LLVM prints the decimal value as if it's two's-complement signed in + # the given bitwidth, so the printed value will be negative if + # greater than 2^(bits - 1) + if value >= (1 << (bits - 1)): + value -= 1 << bits + return ty + str(value) + + +for line in sys.stdin: + print(re.sub(hex, hexReplace, line), end="") diff --git a/utils/lsan_leaks_suppression_list.txt b/utils/lsan_leaks_suppression_list.txt new file mode 100644 index 00000000000..24dd6b9ba41 --- /dev/null +++ b/utils/lsan_leaks_suppression_list.txt @@ -0,0 +1,2 @@ +leak:*buildCompilation* +leak:*llvm::TableGenMain* diff --git a/utils/swift-mode.el b/utils/swift-mode.el index 64306744be8..c533185914f 100644 --- a/utils/swift-mode.el +++ b/utils/swift-mode.el @@ -20,6 +20,11 @@ (set (make-local-variable 'parse-sexp-ignore-comments) t))) +(unless (fboundp 'defvar-local) + (defmacro defvar-local (var val &optional docstring) + "Define VAR as a buffer-local variable with default value VAL." + `(make-variable-buffer-local (defvar ,var ,val ,docstring)))) + ;; Create mode-specific variables (defcustom swift-basic-offset 2 "Default indentation width for Swift source" diff --git a/utils/swift_build_support/swift_build_support/SwiftBuildSupport.py b/utils/swift_build_support/swift_build_support/SwiftBuildSupport.py index 3c94271a4d3..25c84ebfb0e 100644 --- a/utils/swift_build_support/swift_build_support/SwiftBuildSupport.py +++ b/utils/swift_build_support/swift_build_support/SwiftBuildSupport.py @@ -19,7 +19,7 @@ except ImportError: import os -import diagnostics +from . import diagnostics HOME = os.environ.get("HOME", "/") diff --git a/utils/swift_build_support/swift_build_support/__init__.py b/utils/swift_build_support/swift_build_support/__init__.py index 16513fd4658..de37ca00174 100644 --- a/utils/swift_build_support/swift_build_support/__init__.py +++ b/utils/swift_build_support/swift_build_support/__init__.py @@ -20,8 +20,8 @@ from .which import which __all__ = [ "cmake", "debug", + "diagnostics", "migration", - "ninja", "tar", "targets", "toolchain", diff --git a/utils/swift_build_support/swift_build_support/cmake.py b/utils/swift_build_support/swift_build_support/cmake.py index 43d6f141459..78359cd2425 100644 --- a/utils/swift_build_support/swift_build_support/cmake.py +++ b/utils/swift_build_support/swift_build_support/cmake.py @@ -92,6 +92,8 @@ class CMake(object): sanitizers.append('Undefined') if args.enable_tsan: sanitizers.append('Thread') + if args.enable_lsan: + sanitizers.append('Leaks') if sanitizers: define("LLVM_USE_SANITIZER", ";".join(sanitizers)) diff --git a/utils/swift_build_support/swift_build_support/targets.py b/utils/swift_build_support/swift_build_support/targets.py index 1127aab0bcb..ab3e6dccacb 100644 --- a/utils/swift_build_support/swift_build_support/targets.py +++ b/utils/swift_build_support/swift_build_support/targets.py @@ -92,7 +92,7 @@ class StdlibDeploymentTarget(object): iOS = DarwinPlatform("iphoneos", archs=["armv7", "armv7s", "arm64"], sdk_name="IOS") - iOSSimulator = DarwinPlatform("iphonesimulator", archs=["x86_64"], + iOSSimulator = DarwinPlatform("iphonesimulator", archs=["i386", "x86_64"], sdk_name="IOS_SIMULATOR", is_simulator=True) diff --git a/utils/swift_build_support/tests/test_cmake.py b/utils/swift_build_support/tests/test_cmake.py index 65b5d20d75b..eb8a41db4c3 100644 --- a/utils/swift_build_support/tests/test_cmake.py +++ b/utils/swift_build_support/tests/test_cmake.py @@ -33,6 +33,7 @@ class CMakeTestCase(unittest.TestCase): enable_asan=False, enable_ubsan=False, enable_tsan=False, + enable_lsan=False, export_compile_commands=False, distcc=False, cmake_generator="Ninja", @@ -148,6 +149,18 @@ class CMakeTestCase(unittest.TestCase): "-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++", "-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)]) + def test_common_options_lsan(self): + args = self.default_args() + args.enable_lsan = True + cmake = self.cmake(args) + self.assertEqual( + list(cmake.common_options()), + ["-G", "Ninja", + "-DLLVM_USE_SANITIZER=Leaks", + "-DCMAKE_C_COMPILER:PATH=/path/to/clang", + "-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++", + "-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)]) + def test_common_options_export_compile_commands(self): args = self.default_args() args.export_compile_commands = True diff --git a/utils/symbolicate-linux-fatal b/utils/symbolicate-linux-fatal index e6592b618d3..86f77ad4d7d 100755 --- a/utils/symbolicate-linux-fatal +++ b/utils/symbolicate-linux-fatal @@ -74,6 +74,7 @@ def add_lldb_target_modules(lldb_target, memmap): dynlib_path, lldb.LLDB_ARCH_DEFAULT, None, None) lldb_target.SetModuleLoadAddress(module, memmap[dynlib_path]) + lldb_target = None known_memmap = {} @@ -173,7 +174,11 @@ def main(): instack = False stackidx = 0 stack = [] - for line in args.log: + + while True: + line = args.log.readline() + if not line: + break if instack and line.startswith(str(stackidx)): stack.append(line) stackidx = stackidx + 1 diff --git a/utils/update-checkout-config.json b/utils/update-checkout-config.json index 2683626dba1..d251dc88bc7 100644 --- a/utils/update-checkout-config.json +++ b/utils/update-checkout-config.json @@ -130,17 +130,17 @@ "ninja": "release" } }, - "swift-4.0-branch-06-02-2017" : { - "aliases": ["swift-4.0-branch-06-02-2017"], + "swift-4.0-branch-06-23-2017" : { + "aliases": ["swift-4.0-branch-06-23-2017"], "repos": { - "llvm": "swift-4.0-branch-06-02-2017", - "clang": "swift-4.0-branch-06-02-2017", - "swift": "swift-4.0-branch-06-02-2017", - "lldb": "swift-4.0-branch-06-02-2017", + "llvm": "swift-4.0-branch-06-23-2017", + "clang": "swift-4.0-branch-06-23-2017", + "swift": "swift-4.0-branch-06-23-2017", + "lldb": "swift-4.0-branch-06-23-2017", "cmark": "swift-4.0-branch", "llbuild": "swift-4.0-branch", "swiftpm": "swift-4.0-branch", - "compiler-rt": "swift-4.0-branch-06-02-2017", + "compiler-rt": "swift-4.0-branch-06-23-2017", "swift-corelibs-xctest": "swift-4.0-branch", "swift-corelibs-foundation": "swift-4.0-branch", "swift-corelibs-libdispatch": "swift-4.0-branch", diff --git a/utils/update-checkout.cmd b/utils/update-checkout.cmd index 9185ed44394..4593bb40bf5 100644 --- a/utils/update-checkout.cmd +++ b/utils/update-checkout.cmd @@ -1 +1 @@ -python update-checkout %* +python "%~dp0\update-checkout" %* diff --git a/validation-test/IDE/crashers_2/0005-should-have-found-non-type-context-by-now.swift b/validation-test/IDE/crashers_2/0005-should-have-found-non-type-context-by-now.swift index 2ab6c1cea97..67d5606ba37 100644 --- a/validation-test/IDE/crashers_2/0005-should-have-found-non-type-context-by-now.swift +++ b/validation-test/IDE/crashers_2/0005-should-have-found-non-type-context-by-now.swift @@ -2,12 +2,13 @@ // RUN: %target-swift-ide-test -code-completion -code-completion-token=B1 -source-filename=%s // RUN: %target-swift-ide-test -code-completion -code-completion-token=C1 -source-filename=%s -// RUN: not --crash %target-swift-ide-test -code-completion -code-completion-token=A2 -source-filename=%s -// RUN: not --crash %target-swift-ide-test -code-completion -code-completion-token=B2 -source-filename=%s -// RUN: not --crash %target-swift-ide-test -code-completion -code-completion-token=C2 -source-filename=%s +// RUN: %target-swift-ide-test -code-completion -code-completion-token=A2 -source-filename=%s +// RUN: %target-swift-ide-test -code-completion -code-completion-token=B2 -source-filename=%s +// RUN: %target-swift-ide-test -code-completion -code-completion-token=C2 -source-filename=%s // RUN: %target-swift-ide-test -code-completion -code-completion-token=A3 -source-filename=%s // RUN: not --crash %target-swift-ide-test -code-completion -code-completion-token=B3 -source-filename=%s + // REQUIRES: asserts class a1 {} diff --git a/validation-test/IDE/crashers_2/0006-crazy-associated-types.swift b/validation-test/IDE/crashers_2_fixed/0006-crazy-associated-types.swift similarity index 56% rename from validation-test/IDE/crashers_2/0006-crazy-associated-types.swift rename to validation-test/IDE/crashers_2_fixed/0006-crazy-associated-types.swift index 98794c13589..648172a53fb 100644 --- a/validation-test/IDE/crashers_2/0006-crazy-associated-types.swift +++ b/validation-test/IDE/crashers_2_fixed/0006-crazy-associated-types.swift @@ -1,4 +1,4 @@ -// RUN: not --crash %target-swift-ide-test -code-completion -code-completion-token=A -source-filename=%s +// RUN: %target-swift-ide-test -code-completion -code-completion-token=A -source-filename=%s // REQUIRES: asserts protocol a { diff --git a/validation-test/Reflection/inherits_NSObject.swift b/validation-test/Reflection/inherits_NSObject.swift index 3fd3ade7670..208d301e410 100644 --- a/validation-test/Reflection/inherits_NSObject.swift +++ b/validation-test/Reflection/inherits_NSObject.swift @@ -23,12 +23,12 @@ reflect(object: baseClass) // CHECK-64: (class inherits_NSObject.BaseNSClass) // CHECK-64: Type info: -// CHECK-64-NEXT: (class_instance size=25 alignment=8 stride=32 num_extra_inhabitants=0 -// CHECK-64-NEXT: (field name=w offset=16 +// CHECK-64-NEXT: (class_instance size=17 alignment=8 stride=24 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=w offset=8 // CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 // CHECK-64-NEXT: (field name=_value offset=0 // CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0)))) -// CHECK-64-NEXT: (field name=x offset=24 +// CHECK-64-NEXT: (field name=x offset=16 // CHECK-64-NEXT: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=254 // CHECK-64-NEXT: (field name=_value offset=0 // CHECK-64-NEXT: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=254))))) @@ -38,12 +38,12 @@ reflect(object: baseClass) // CHECK-32: (class inherits_NSObject.BaseNSClass) // CHECK-32: Type info: -// CHECK-32-NEXT: (class_instance size=17 alignment=4 stride=20 num_extra_inhabitants=0 -// CHECK-32-NEXT: (field name=w offset=12 +// CHECK-32-NEXT: (class_instance size=9 alignment=4 stride=12 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=w offset=4 // CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 // CHECK-32-NEXT: (field name=_value offset=0 // CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))) -// CHECK-32-NEXT: (field name=x offset=16 +// CHECK-32-NEXT: (field name=x offset=8 // CHECK-32-NEXT: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=254 // CHECK-32-NEXT: (field name=_value offset=0 // CHECK-32-NEXT: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=254))))) @@ -61,12 +61,12 @@ reflect(object: derivedClass) // CHECK-64: (class inherits_NSObject.DerivedNSClass) // CHECK-64: Type info: -// CHECK-64-NEXT: (class_instance size=40 alignment=8 stride=40 num_extra_inhabitants=0 -// CHECK-64-NEXT: (field name=y offset=25 +// CHECK-64-NEXT: (class_instance size=32 alignment=8 stride=32 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=y offset=17 // CHECK-64-NEXT: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=254 // CHECK-64-NEXT: (field name=_value offset=0 // CHECK-64-NEXT: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=254)))) -// CHECK-64-NEXT: (field name=z offset=32 +// CHECK-64-NEXT: (field name=z offset=24 // CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 // CHECK-64-NEXT: (field name=_value offset=0 // CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0))))) @@ -76,12 +76,12 @@ reflect(object: derivedClass) // CHECK-32: (class inherits_NSObject.DerivedNSClass) // CHECK-32: Type info: -// CHECK-32-NEXT: (class_instance size=24 alignment=4 stride=24 num_extra_inhabitants=0 -// CHECK-32-NEXT: (field name=y offset=17 +// CHECK-32-NEXT: (class_instance size=16 alignment=4 stride=16 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=y offset=9 // CHECK-32-NEXT: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=254 // CHECK-32-NEXT: (field name=_value offset=0 // CHECK-32-NEXT: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=254)))) -// CHECK-32-NEXT: (field name=z offset=20 +// CHECK-32-NEXT: (field name=z offset=12 // CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 // CHECK-32-NEXT: (field name=_value offset=0 // CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0))))) @@ -131,12 +131,12 @@ reflect(object: alignedClass) // CHECK-64: (class inherits_NSObject.AlignedNSClass) // CHECK-64: Type info: -// CHECK-64-NEXT: (class_instance size=48 alignment=16 stride=48 num_extra_inhabitants=0 -// CHECK-64-NEXT: (field name=w offset=16 +// CHECK-64-NEXT: (class_instance size=32 alignment=16 stride=32 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=w offset=8 // CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 // CHECK-64-NEXT: (field name=_value offset=0 // CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0)))) -// CHECK-64-NEXT: (field name=x offset=32 +// CHECK-64-NEXT: (field name=x offset=16 // CHECK-64-NEXT: (builtin size=16 alignment=16 stride=16 num_extra_inhabitants=0))) // CHECK-32: Reflecting an object. @@ -145,7 +145,7 @@ reflect(object: alignedClass) // CHECK-32: Type info: // CHECK-32-NEXT: (class_instance size=32 alignment=16 stride=32 num_extra_inhabitants=0 -// CHECK-32-NEXT: (field name=w offset=12 +// CHECK-32-NEXT: (field name=w offset=4 // CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 // CHECK-32-NEXT: (field name=_value offset=0 // CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))) diff --git a/validation-test/Reflection/inherits_ObjCClasses.swift b/validation-test/Reflection/inherits_ObjCClasses.swift index f9ceb5862ed..8b569c9e3c6 100644 --- a/validation-test/Reflection/inherits_ObjCClasses.swift +++ b/validation-test/Reflection/inherits_ObjCClasses.swift @@ -61,8 +61,8 @@ reflect(object: firstClassB) // CHECK-32: (class inherits_ObjCClasses.FirstClassB) // CHECK-32: Type info: -// CHECK-32-NEXT: (class_instance size=16 alignment=4 stride=16 num_extra_inhabitants=0 -// CHECK-32-NEXT: (field name=zz offset=12 +// CHECK-32-NEXT: (class_instance size=12 alignment=4 stride=12 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=zz offset=8 // CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 // CHECK-32-NEXT: (field name=_value offset=0 // CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0))))) diff --git a/validation-test/Reflection/reflect_Character.swift b/validation-test/Reflection/reflect_Character.swift index 9fcda45dee6..d6911ede41b 100644 --- a/validation-test/Reflection/reflect_Character.swift +++ b/validation-test/Reflection/reflect_Character.swift @@ -7,9 +7,6 @@ // FIXME: https://bugs.swift.org/browse/SR-2808 // XFAIL: resilient_stdlib -// See https://bugs.swift.org/browse/SR-5066, rdar://32511557 -// XFAIL: * - import SwiftReflectionTest class TestClass { @@ -24,7 +21,6 @@ var obj = TestClass(t: "A") reflect(object: obj) // CHECK-64: Reflecting an object. -// CHECK-64: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}} // CHECK-64: Type reference: // CHECK-64: (class reflect_Character.TestClass) @@ -33,35 +29,30 @@ reflect(object: obj) // CHECK-64-NEXT: (field name=t offset=16 // CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 // CHECK-64-NEXT: (field name=_representation offset=0 -// CHECK-64-NEXT: (multi_payload_enum size=9 alignment=8 stride=16 num_extra_inhabitants=0 +// CHECK-64-NEXT: (multi_payload_enum size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=smallUTF16 offset=0 +// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=2147483647)) // CHECK-64-NEXT: (field name=large offset=0 -// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=2147483646 -// CHECK-64-NEXT: (field name=_storage offset=0 -// CHECK-64-NEXT: (single_payload_enum size=8 alignment=8 stride=8 num_extra_inhabitants=2147483646 -// CHECK-64-NEXT: (field name=some offset=0 -// CHECK-64-NEXT: (reference kind=strong refcounting=native)))))) -// CHECK-64-NEXT: (field name=small offset=0 -// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=2147483647))))))) +// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=2147483647 +// CHECK-64-NEXT: (field name=_nativeBuffer offset=0 +// CHECK-64-NEXT: (reference kind=strong refcounting=native))))))))) // CHECK-32: Reflecting an object. -// CHECK-32: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}} // CHECK-32: Type reference: // CHECK-32: (class reflect_Character.TestClass) // CHECK-32: Type info: -// CHECK-32: (class_instance size=24 alignment=8 stride=24 num_extra_inhabitants=0 -// CHECK-32: (field name=t offset=16 -// CHECK-32: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 -// CHECK-32: (field name=_representation offset=0 -// CHECK-32: (multi_payload_enum size=8 alignment=8 stride=8 num_extra_inhabitants=0 -// CHECK-32: (field name=large offset=0 -// CHECK-32: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=4095 -// CHECK-32: (field name=_storage offset=0 -// CHECK-32: (single_payload_enum size=4 alignment=4 stride=4 num_extra_inhabitants=4095 -// CHECK-32: (field name=some offset=0 -// CHECK-32: (reference kind=strong refcounting=native)))))) -// CHECK-32: (field name=small offset=0 -// CHECK-32: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=2147483647))))))) +// CHECK-32-NEXT: (class_instance size=24 alignment=8 stride=24 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=t offset=16 +// CHECK-32-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=_representation offset=0 +// CHECK-32-NEXT: (multi_payload_enum size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=smallUTF16 offset=0 +// CHECK-32-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=2147483647)) +// CHECK-32-NEXT: (field name=large offset=0 +// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=4096 +// CHECK-32-NEXT: (field name=_nativeBuffer offset=0 +// CHECK-32-NEXT: (reference kind=strong refcounting=native))))))))) doneReflecting() diff --git a/validation-test/Reflection/reflect_multiple_types.swift b/validation-test/Reflection/reflect_multiple_types.swift index 6f76f81a39d..bdcfba9c540 100644 --- a/validation-test/Reflection/reflect_multiple_types.swift +++ b/validation-test/Reflection/reflect_multiple_types.swift @@ -7,9 +7,6 @@ // FIXME: https://bugs.swift.org/browse/SR-2808 // XFAIL: resilient_stdlib -// See https://bugs.swift.org/browse/SR-5066, rdar://32511557 -// XFAIL: * - import SwiftReflectionTest import Foundation @@ -118,91 +115,89 @@ reflect(object: obj) // CHECK-64: (class reflect_multiple_types.TestClass) // CHECK-64: Type info: -// CHECK-64: (class_instance size=185 alignment=8 stride=192 num_extra_inhabitants=0 -// CHECK-64: (field name=t00 offset=16 -// CHECK-64: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=1 +// CHECK-64-NEXT: (class_instance size=185 alignment=8 stride=192 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=t00 offset=16 +// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=1 // (unstable implementation details omitted) // CHECK-64: (field name=t01 offset=24 -// CHECK-64: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=254 -// CHECK-64: (field name=_value offset=0 -// CHECK-64: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=254)))) -// CHECK-64: (field name=t02 offset=32 -// CHECK-64: (struct size=9 alignment=8 stride=16 num_extra_inhabitants=0 -// CHECK-64: (field name=_representation offset=0 -// CHECK-64: (multi_payload_enum size=9 alignment=8 stride=16 num_extra_inhabitants=0 -// CHECK-64: (field name=large offset=0 -// CHECK-64: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=2147483646 -// CHECK-64: (field name=_storage offset=0 -// CHECK-64: (single_payload_enum size=8 alignment=8 stride=8 num_extra_inhabitants=2147483646 -// CHECK-64: (field name=some offset=0 -// CHECK-64: (reference kind=strong refcounting=native)))))) -// CHECK-64: (field name=small offset=0 -// CHECK-64: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=2147483647)))))) -// CHECK-64: (field name=t03 offset=48 -// CHECK-64: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-64-NEXT: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=254 +// CHECK-64-NEXT: (field name=_value offset=0 +// CHECK-64-NEXT: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=254)))) +// CHECK-64-NEXT: (field name=t02 offset=32 +// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=_representation offset=0 +// CHECK-64-NEXT: (multi_payload_enum size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=smallUTF16 offset=0 +// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=2147483647)) +// CHECK-64-NEXT: (field name=large offset=0 +// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=2147483647 +// CHECK-64-NEXT: (field name=_nativeBuffer offset=0 +// CHECK-64-NEXT: (reference kind=strong refcounting=native)))) +// CHECK-64-NEXT: (field name=t03 offset=40 +// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 // (unstable implementation details omitted) -// CHECK-64: (field name=t04 offset=56 -// CHECK-64: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 -// CHECK-64: (field name=_value offset=0 -// CHECK-64: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0)))) -// CHECK-64: (field name=t05 offset=64 -// CHECK-64: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 -// CHECK-64: (field name=_value offset=0 -// CHECK-64: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))) -// CHECK-64: (field name=t06 offset=72 -// CHECK-64: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 -// CHECK-64: (field name=_value offset=0 -// CHECK-64: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0)))) -// CHECK-64: (field name=t07 offset=80 -// CHECK-64: (struct size=2 alignment=2 stride=2 num_extra_inhabitants=0 -// CHECK-64: (field name=_value offset=0 -// CHECK-64: (builtin size=2 alignment=2 stride=2 num_extra_inhabitants=0)))) -// CHECK-64: (field name=t08 offset=84 -// CHECK-64: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 -// CHECK-64: (field name=_value offset=0 -// CHECK-64: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))) -// CHECK-64: (field name=t09 offset=88 -// CHECK-64: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 -// CHECK-64: (field name=_value offset=0 -// CHECK-64: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0)))) -// CHECK-64: (field name=t10 offset=96 -// CHECK-64: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=0 -// CHECK-64: (field name=_value offset=0 -// CHECK-64: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=0)))) -// CHECK-64: (field name=t11 offset=104 -// CHECK-64: (reference kind=strong refcounting=unknown)) -// CHECK-64: (field name=t12 offset=112 -// CHECK-64: (reference kind=strong refcounting=unknown)) -// CHECK-64: (field name=t13 offset=120 -// CHECK-64: (reference kind=strong refcounting=unknown)) -// CHECK-64: (field name=t14 offset=128 -// CHECK-64: (reference kind=strong refcounting=unknown)) -// CHECK-64: (field name=t15 offset=136 -// CHECK-64: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-64: (field name=t04 offset=48 +// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=_value offset=0 +// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0)))) +// CHECK-64-NEXT: (field name=t05 offset=56 +// CHECK-64-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=_value offset=0 +// CHECK-64-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))) +// CHECK-64-NEXT: (field name=t06 offset=64 +// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=_value offset=0 +// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0)))) +// CHECK-64-NEXT: (field name=t07 offset=72 +// CHECK-64-NEXT: (struct size=2 alignment=2 stride=2 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=_value offset=0 +// CHECK-64-NEXT: (builtin size=2 alignment=2 stride=2 num_extra_inhabitants=0)))) +// CHECK-64-NEXT: (field name=t08 offset=76 +// CHECK-64-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=_value offset=0 +// CHECK-64-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))) +// CHECK-64-NEXT: (field name=t09 offset=80 +// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=_value offset=0 +// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0)))) +// CHECK-64-NEXT: (field name=t10 offset=88 +// CHECK-64-NEXT: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=_value offset=0 +// CHECK-64-NEXT: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=0)))) +// CHECK-64-NEXT: (field name=t11 offset=96 +// CHECK-64-NEXT: (reference kind=strong refcounting=unknown)) +// CHECK-64-NEXT: (field name=t12 offset=104 +// CHECK-64-NEXT: (reference kind=strong refcounting=unknown)) +// CHECK-64-NEXT: (field name=t13 offset=112 +// CHECK-64-NEXT: (reference kind=strong refcounting=unknown)) +// CHECK-64-NEXT: (field name=t14 offset=120 +// CHECK-64-NEXT: (reference kind=strong refcounting=unknown)) +// CHECK-64-NEXT: (field name=t15 offset=128 +// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 // (unstable implementation details omitted) -// CHECK-64: (field name=t16 offset=144 -// CHECK-64: (struct size=24 alignment=8 stride=24 num_extra_inhabitants=0 +// CHECK-64: (field name=t16 offset=136 +// CHECK-64-NEXT: (struct size=24 alignment=8 stride=24 num_extra_inhabitants=0 // (unstable implementation details omitted) -// CHECK-64: (field name=t17 offset=168 -// CHECK-64: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 -// CHECK-64: (field name=_value offset=0 -// CHECK-64: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0)))) -// CHECK-64: (field name=t18 offset=176 -// CHECK-64: (struct size=2 alignment=2 stride=2 num_extra_inhabitants=0 -// CHECK-64: (field name=_value offset=0 -// CHECK-64: (builtin size=2 alignment=2 stride=2 num_extra_inhabitants=0)))) -// CHECK-64: (field name=t19 offset=180 -// CHECK-64: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 -// CHECK-64: (field name=_value offset=0 -// CHECK-64: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))) -// CHECK-64: (field name=t20 offset=184 -// CHECK-64: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 -// CHECK-64: (field name=_value offset=0 -// CHECK-64: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0)))) -// CHECK-64: (field name=t21 offset=192 -// CHECK-64: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=0 -// CHECK-64: (field name=_value offset=0 -// CHECK-64: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=0))))) +// CHECK-64: (field name=t17 offset=160 +// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=_value offset=0 +// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0)))) +// CHECK-64-NEXT: (field name=t18 offset=168 +// CHECK-64-NEXT: (struct size=2 alignment=2 stride=2 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=_value offset=0 +// CHECK-64-NEXT: (builtin size=2 alignment=2 stride=2 num_extra_inhabitants=0)))) +// CHECK-64-NEXT: (field name=t19 offset=172 +// CHECK-64-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=_value offset=0 +// CHECK-64-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))) +// CHECK-64-NEXT: (field name=t20 offset=176 +// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=_value offset=0 +// CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0)))) +// CHECK-64-NEXT: (field name=t21 offset=184 +// CHECK-64-NEXT: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=0 +// CHECK-64-NEXT: (field name=_value offset=0 +// CHECK-64-NEXT: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=0))))) // CHECK-32: Reflecting an object. // CHECK-32: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}} @@ -210,91 +205,89 @@ reflect(object: obj) // CHECK-32: (class reflect_multiple_types.TestClass) // CHECK-32: Type info: -// CHECK-32: (class_instance size=129 alignment=8 stride=136 num_extra_inhabitants=0 -// CHECK-32: (field name=t00 offset=12 -// CHECK-32: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=1 +// CHECK-32-NEXT: (class_instance size=129 alignment=8 stride=136 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=t00 offset=12 +// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=1 // (unstable implementation details omitted) // CHECK-32: (field name=t01 offset=16 -// CHECK-32: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=254 -// CHECK-32: (field name=_value offset=0 -// CHECK-32: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=254)))) -// CHECK-32: (field name=t02 offset=24 -// CHECK-32: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 -// CHECK-32: (field name=_representation offset=0 -// CHECK-32: (multi_payload_enum size=8 alignment=8 stride=8 num_extra_inhabitants=0 -// CHECK-32: (field name=large offset=0 -// CHECK-32: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=4095 -// CHECK-32: (field name=_storage offset=0 -// CHECK-32: (single_payload_enum size=4 alignment=4 stride=4 num_extra_inhabitants=4095 -// CHECK-32: (field name=some offset=0 -// CHECK-32: (reference kind=strong refcounting=native)))))) -// CHECK-32: (field name=small offset=0 -// CHECK-32: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=2147483647)))))) -// CHECK-32: (field name=t03 offset=32 -// CHECK-32: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 +// CHECK-32-NEXT: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=254 +// CHECK-32-NEXT: (field name=_value offset=0 +// CHECK-32-NEXT: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=254)))) +// CHECK-32-NEXT: (field name=t02 offset=24 +// CHECK-32-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=_representation offset=0 +// CHECK-32-NEXT: (multi_payload_enum size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=smallUTF16 offset=0 +// CHECK-32-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=2147483647)) +// CHECK-32-NEXT: (field name=large offset=0 +// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=4096 +// CHECK-32-NEXT: (field name=_nativeBuffer offset=0 +// CHECK-32-NEXT: (reference kind=strong refcounting=native)))))) +// CHECK-32-NEXT: (field name=t03 offset=32 +// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 // (unstable implementation details omitted) // CHECK-32: (field name=t04 offset=40 -// CHECK-32: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 -// CHECK-32: (field name=_value offset=0 -// CHECK-32: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0)))) -// CHECK-32: (field name=t05 offset=48 -// CHECK-32: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 -// CHECK-32: (field name=_value offset=0 -// CHECK-32: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))) -// CHECK-32: (field name=t06 offset=52 -// CHECK-32: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 -// CHECK-32: (field name=_value offset=0 -// CHECK-32: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))) -// CHECK-32: (field name=t07 offset=56 -// CHECK-32: (struct size=2 alignment=2 stride=2 num_extra_inhabitants=0 -// CHECK-32: (field name=_value offset=0 -// CHECK-32: (builtin size=2 alignment=2 stride=2 num_extra_inhabitants=0)))) -// CHECK-32: (field name=t08 offset=60 -// CHECK-32: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 -// CHECK-32: (field name=_value offset=0 -// CHECK-32: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))) -// CHECK-32: (field name=t09 offset=64 -// CHECK-32: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 -// CHECK-32: (field name=_value offset=0 -// CHECK-32: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0)))) -// CHECK-32: (field name=t10 offset=72 -// CHECK-32: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=0 -// CHECK-32: (field name=_value offset=0 -// CHECK-32: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=0)))) -// CHECK-32: (field name=t11 offset=76 -// CHECK-32: (reference kind=strong refcounting=unknown)) -// CHECK-32: (field name=t12 offset=80 -// CHECK-32: (reference kind=strong refcounting=unknown)) -// CHECK-32: (field name=t13 offset=84 -// CHECK-32: (reference kind=strong refcounting=unknown)) -// CHECK-32: (field name=t14 offset=88 -// CHECK-32: (reference kind=strong refcounting=unknown)) -// CHECK-32: (field name=t15 offset=92 -// CHECK-32: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 +// CHECK-32-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=_value offset=0 +// CHECK-32-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0)))) +// CHECK-32-NEXT: (field name=t05 offset=48 +// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=_value offset=0 +// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))) +// CHECK-32-NEXT: (field name=t06 offset=52 +// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=_value offset=0 +// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))) +// CHECK-32-NEXT: (field name=t07 offset=56 +// CHECK-32-NEXT: (struct size=2 alignment=2 stride=2 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=_value offset=0 +// CHECK-32-NEXT: (builtin size=2 alignment=2 stride=2 num_extra_inhabitants=0)))) +// CHECK-32-NEXT: (field name=t08 offset=60 +// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=_value offset=0 +// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))) +// CHECK-32-NEXT: (field name=t09 offset=64 +// CHECK-32-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=_value offset=0 +// CHECK-32-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0)))) +// CHECK-32-NEXT: (field name=t10 offset=72 +// CHECK-32-NEXT: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=_value offset=0 +// CHECK-32-NEXT: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=0)))) +// CHECK-32-NEXT: (field name=t11 offset=76 +// CHECK-32-NEXT: (reference kind=strong refcounting=unknown)) +// CHECK-32-NEXT: (field name=t12 offset=80 +// CHECK-32-NEXT: (reference kind=strong refcounting=unknown)) +// CHECK-32-NEXT: (field name=t13 offset=84 +// CHECK-32-NEXT: (reference kind=strong refcounting=unknown)) +// CHECK-32-NEXT: (field name=t14 offset=88 +// CHECK-32-NEXT: (reference kind=strong refcounting=unknown)) +// CHECK-32-NEXT: (field name=t15 offset=92 +// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 // (unstable implementation details omitted) // CHECK-32: (field name=t16 offset=96 -// CHECK-32: (struct size=12 alignment=4 stride=12 num_extra_inhabitants=0 +// CHECK-32-NEXT: (struct size=12 alignment=4 stride=12 num_extra_inhabitants=0 // (unstable implementation details omitted) // CHECK-32: (field name=t17 offset=108 -// CHECK-32: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 -// CHECK-32: (field name=_value offset=0 -// CHECK-32: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))) -// CHECK-32: (field name=t18 offset=112 -// CHECK-32: (struct size=2 alignment=2 stride=2 num_extra_inhabitants=0 -// CHECK-32: (field name=_value offset=0 -// CHECK-32: (builtin size=2 alignment=2 stride=2 num_extra_inhabitants=0)))) -// CHECK-32: (field name=t19 offset=116 -// CHECK-32: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 -// CHECK-32: (field name=_value offset=0 -// CHECK-32: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))) -// CHECK-32: (field name=t20 offset=120 -// CHECK-32: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 -// CHECK-32: (field name=_value offset=0 -// CHECK-32: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0)))) -// CHECK-32: (field name=t21 offset=128 -// CHECK-32: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=0 -// CHECK-32: (field name=_value offset=0 -// CHECK-32: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=0))))) +// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=_value offset=0 +// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))) +// CHECK-32-NEXT: (field name=t18 offset=112 +// CHECK-32-NEXT: (struct size=2 alignment=2 stride=2 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=_value offset=0 +// CHECK-32-NEXT: (builtin size=2 alignment=2 stride=2 num_extra_inhabitants=0)))) +// CHECK-32-NEXT: (field name=t19 offset=116 +// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=_value offset=0 +// CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0)))) +// CHECK-32-NEXT: (field name=t20 offset=120 +// CHECK-32-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=_value offset=0 +// CHECK-32-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0)))) +// CHECK-32-NEXT: (field name=t21 offset=128 +// CHECK-32-NEXT: (struct size=1 alignment=1 stride=1 num_extra_inhabitants=0 +// CHECK-32-NEXT: (field name=_value offset=0 +// CHECK-32-NEXT: (builtin size=1 alignment=1 stride=1 num_extra_inhabitants=0))))) doneReflecting() diff --git a/validation-test/compiler_crashers/28776-type-should-have-type-checked-inheritance-clause-by-now.swift b/validation-test/compiler_crashers/28776-type-should-have-type-checked-inheritance-clause-by-now.swift new file mode 100644 index 00000000000..d3929f76247 --- /dev/null +++ b/validation-test/compiler_crashers/28776-type-should-have-type-checked-inheritance-clause-by-now.swift @@ -0,0 +1,13 @@ +// This source file is part of the Swift.org open source project +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + +// REQUIRES: asserts +// RUN: not --crash %target-swift-frontend %s -emit-ir +protocol P{typealias a{}class a +{}typealias a{}class a +}{extension{class a:P +protocol A:A diff --git a/validation-test/compiler_crashers/28777-swift-typebase-getcanonicaltype.swift b/validation-test/compiler_crashers/28777-swift-typebase-getcanonicaltype.swift new file mode 100644 index 00000000000..da2c76269e6 --- /dev/null +++ b/validation-test/compiler_crashers/28777-swift-typebase-getcanonicaltype.swift @@ -0,0 +1,11 @@ +// This source file is part of the Swift.org open source project +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + +// RUN: not --crash %target-swift-frontend %s -emit-ir +{ +f +typealias a:b{}var f=a.a diff --git a/validation-test/compiler_crashers/28778-hasaccessibility-accessibility-not-computed-yet.swift b/validation-test/compiler_crashers/28778-hasaccessibility-accessibility-not-computed-yet.swift new file mode 100644 index 00000000000..6bf0b843f13 --- /dev/null +++ b/validation-test/compiler_crashers/28778-hasaccessibility-accessibility-not-computed-yet.swift @@ -0,0 +1,10 @@ +// This source file is part of the Swift.org open source project +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + +// REQUIRES: asserts +// RUN: not --crash %target-swift-frontend %s -emit-ir +extension{let d=r protocol A{{}extension{func<(Int= diff --git a/validation-test/compiler_crashers/28779-parent-parent-is-nominaltype-parent-is-boundgenerictype-parent-is-unboundgeneric.swift b/validation-test/compiler_crashers/28779-parent-parent-is-nominaltype-parent-is-boundgenerictype-parent-is-unboundgeneric.swift new file mode 100644 index 00000000000..631ea5a7a30 --- /dev/null +++ b/validation-test/compiler_crashers/28779-parent-parent-is-nominaltype-parent-is-boundgenerictype-parent-is-unboundgeneric.swift @@ -0,0 +1,10 @@ +// This source file is part of the Swift.org open source project +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + +// REQUIRES: asserts +// RUN: not --crash %target-swift-frontend %s -emit-ir +protocol P{func a:Self.a.a{}class a{class a diff --git a/validation-test/compiler_crashers/28780-hasinterfacetype-no-interface-type-was-set.swift b/validation-test/compiler_crashers/28780-hasinterfacetype-no-interface-type-was-set.swift new file mode 100644 index 00000000000..3cd2147862e --- /dev/null +++ b/validation-test/compiler_crashers/28780-hasinterfacetype-no-interface-type-was-set.swift @@ -0,0 +1,10 @@ +// This source file is part of the Swift.org open source project +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + +// REQUIRES: asserts +// RUN: not --crash %target-swift-frontend %s -emit-ir +class a{func a:A.a:class A:a{{}func a diff --git a/validation-test/compiler_crashers/28782-superclass-superclass-isequal-t-should-have-diagnosed-multiple-superclasses-by-n.swift b/validation-test/compiler_crashers/28782-superclass-superclass-isequal-t-should-have-diagnosed-multiple-superclasses-by-n.swift new file mode 100644 index 00000000000..1b7f74bac86 --- /dev/null +++ b/validation-test/compiler_crashers/28782-superclass-superclass-isequal-t-should-have-diagnosed-multiple-superclasses-by-n.swift @@ -0,0 +1,12 @@ +// This source file is part of the Swift.org open source project +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + +// REQUIRES: asserts +// RUN: not --crash %target-swift-frontend %s -emit-ir +[.a{}ExtendedGraphemeClusterLiteralConvertible +& ManagedBuffer +& ManagedBuffer diff --git a/validation-test/compiler_crashers/28783-hasconformanceinsignature-inprotocol-getrequirementsignature-subjecttype-conform.swift b/validation-test/compiler_crashers/28783-hasconformanceinsignature-inprotocol-getrequirementsignature-subjecttype-conform.swift new file mode 100644 index 00000000000..bcd5e1c95b9 --- /dev/null +++ b/validation-test/compiler_crashers/28783-hasconformanceinsignature-inprotocol-getrequirementsignature-subjecttype-conform.swift @@ -0,0 +1,12 @@ +// This source file is part of the Swift.org open source project +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + +// REQUIRES: asserts +// RUN: not --crash %target-swift-frontend %s -emit-ir +class a:A +protocol A:a{ +protocol A{struct a{var f:A diff --git a/validation-test/compiler_crashers/28784-genericsigorenv-isnull-getgenericsignature-getcanonicalsignature-genericenv-getg.swift b/validation-test/compiler_crashers/28784-genericsigorenv-isnull-getgenericsignature-getcanonicalsignature-genericenv-getg.swift new file mode 100644 index 00000000000..3fc4fbd93c9 --- /dev/null +++ b/validation-test/compiler_crashers/28784-genericsigorenv-isnull-getgenericsignature-getcanonicalsignature-genericenv-getg.swift @@ -0,0 +1,10 @@ +// This source file is part of the Swift.org open source project +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + +// REQUIRES: asserts +// RUN: not --crash %target-swift-frontend %s -emit-ir +extension P{{}}protocol P{protocol P{protocol A{{}typealias a{}}typealias e:A.a}typealias e:P diff --git a/validation-test/compiler_crashers/28785-membertype-received-null-dependent-member-type.swift b/validation-test/compiler_crashers/28785-membertype-received-null-dependent-member-type.swift new file mode 100644 index 00000000000..80f25a3f43a --- /dev/null +++ b/validation-test/compiler_crashers/28785-membertype-received-null-dependent-member-type.swift @@ -0,0 +1,10 @@ +// This source file is part of the Swift.org open source project +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + +// REQUIRES: asserts +// RUN: not --crash %target-swift-frontend %s -emit-ir +protocol b{{}class a { + @_versioned + var _storage: Storage + @_versioned + var _bitCount: UInt8 + + @inline(__always) + @_versioned + internal init(_storage: Storage, _bitCount: UInt8) { + self._storage = _storage + self._bitCount = _bitCount + } + + @inline(__always) + public init(containing e: Element) { + _storage = Storage(extendingOrTruncating: e) + _bitCount = UInt8(extendingOrTruncating: Element.bitWidth) + } +} + +extension _UIntBuffer : Sequence { + @_fixed_layout + public struct Iterator : IteratorProtocol, Sequence { + @inline(__always) + public init(_ x: _UIntBuffer) { _impl = x } + + @inline(__always) + public mutating func next() -> Element? { + if _impl._bitCount == 0 { return nil } + defer { + _impl._storage = _impl._storage &>> Element.bitWidth + _impl._bitCount = _impl._bitCount &- _impl._elementWidth + } + return Element(extendingOrTruncating: _impl._storage) + } + @_versioned + var _impl: _UIntBuffer + } + + @inline(__always) + public func makeIterator() -> Iterator { + return Iterator(self) + } + + @inline(__always) + public func reversed() -> _UIntBuffer { + if Element.bitWidth == 8 { + return _UIntBuffer( + _storage: + storage.byteSwapped &>> (Storage.bitWidth &- numericCast(_bitCount)), + _bitCount: _bitCount) + } + else { + var s: Storage = 0 + for x in self { + s <<= Element.bitWidth + s |= Storage(extendingOrTruncating: x) + } + return Self(_storage: s, _bitCount: _bitCount) + } + } +} + +extension _UIntBuffer : Collection { + public typealias _Element = Element + + public struct Index : Comparable { + @_versioned + var bitOffset: UInt8 + + @_versioned + init(bitOffset: UInt8) { self.bitOffset = bitOffset } + + public static func == (lhs: Index, rhs: Index) -> Bool { + return lhs.bitOffset == rhs.bitOffset + } + public static func < (lhs: Index, rhs: Index) -> Bool { + return lhs.bitOffset < rhs.bitOffset + } + } + + public var startIndex : Index { + @inline(__always) + get { return Index(bitOffset: 0) } + } + + public var endIndex : Index { + @inline(__always) + get { return Index(bitOffset: _bitCount) } + } + + @inline(__always) + public func index(after i: Index) -> Index { + return Index(bitOffset: i.bitOffset &+ _elementWidth) + } + + @_versioned + internal var _elementWidth : UInt8 { + return UInt8(extendingOrTruncating: Element.bitWidth) + } + + public subscript(i: Index) -> Element { + @inline(__always) + get { + return Element(extendingOrTruncating: _storage &>> i.bitOffset) + } + } +} + +extension _UIntBuffer : BidirectionalCollection { + @inline(__always) + public func index(before i: Index) -> Index { + return Index(bitOffset: i.bitOffset &- _elementWidth) + } +} + +extension _UIntBuffer : RandomAccessCollection { + public typealias Indices = DefaultRandomAccessIndices<_UIntBuffer> + public typealias IndexDistance = Int + + @inline(__always) + public func index(_ i: Index, offsetBy n: IndexDistance) -> Index { + let x = IndexDistance(i.bitOffset) &+ n &* Element.bitWidth + return Index(bitOffset: UInt8(extendingOrTruncating: x)) + } + + @inline(__always) + public func distance(from i: Index, to j: Index) -> IndexDistance { + return (Int(j.bitOffset) &- Int(i.bitOffset)) / Element.bitWidth + } +} + +extension FixedWidthInteger { + @inline(__always) + @_versioned + func _fullShiftLeft(_ n: N) -> Self { + return (self &<< ((n &+ 1) &>> 1)) &<< (n &>> 1) + } + @inline(__always) + @_versioned + func _fullShiftRight(_ n: N) -> Self { + return (self &>> ((n &+ 1) &>> 1)) &>> (n &>> 1) + } + @inline(__always) + @_versioned + static func _lowBits(_ n: N) -> Self { + return ~((~0 as Self)._fullShiftLeft(n)) + } +} + +extension Range { + @inline(__always) + @_versioned + func _contains_(_ other: Range) -> Bool { + return other.clamped(to: self) == other + } +} + +extension _UIntBuffer : RangeReplaceableCollection { + @inline(__always) + public init() { + _storage = 0 + _bitCount = 0 + } + + public var capacity: Int { + return Storage.bitWidth / Element.bitWidth + } + + @inline(__always) + public mutating func append(_ newElement: Element) { + _debugPrecondition(count < capacity) + _storage |= Storage(newElement) &<< _bitCount + _bitCount = _bitCount &+ _elementWidth + } + + @inline(__always) + public mutating func replaceSubrange( + _ target: Range, with replacement: C + ) where C._Element == Element { + _debugPrecondition( + (0..<_bitCount)._contains_( + target.lowerBound.bitOffset.. = (T, consumedCodeUnits: UInt8, isValid: Bool) +} + +public protocol UnicodeDecoder { + associatedtype CodeUnit : UnsignedInteger, FixedWidthInteger + associatedtype EncodedScalar : BidirectionalCollection + where EncodedScalar.Iterator.Element == CodeUnit + + init() + + mutating func parseOne( + _ input: inout I + ) -> Unicode.ParseResult where I.Element == CodeUnit +} + +extension UnicodeDecoder { + @inline(__always) + @discardableResult + public static func decode( + _ input: inout I, + repairingIllFormedSequences makeRepairs: Bool, + into output: (UnicodeScalar)->Void + ) -> Int + where I.Element == CodeUnit + { + var errors = 0 + var d = Self() + while true { + switch d.parseOne(&input) { + case let .valid(scalarContent): + output(decodeOne(scalarContent)) + case .invalid: + if !makeRepairs { return 1 } + errors += 1 + output(UnicodeScalar(_unchecked: 0xFFFD)) + case .emptyInput: + return errors + } + } + } +} + + +extension Unicode { + struct ParsingIterator< + CodeUnitIterator : IteratorProtocol, + Encoding: UnicodeEncoding, + Decoder: UnicodeDecoder + > where Decoder.CodeUnit == CodeUnitIterator.Element, + Encoding.EncodedScalar == Decoder.EncodedScalar { + var codeUnits: CodeUnitIterator + var decoder: Decoder + } +} +extension Unicode.ParsingIterator : IteratorProtocol, Sequence { + mutating func next() -> Decoder.EncodedScalar? { + switch decoder.parseOne(&codeUnits) { + case let .valid(scalarContent): return scalarContent + case .invalid: return Encoding.encodedReplacementScalar + case .emptyInput: return nil + } + } +} + +extension Unicode { + struct DefaultScalarView< + CodeUnits: BidirectionalCollection, + Encoding: UnicodeEncoding + > where CodeUnits.Iterator.Element == Encoding.CodeUnit { + var codeUnits: CodeUnits + init( + _ codeUnits: CodeUnits, + fromEncoding _: Encoding.Type = Encoding.self) { + self.codeUnits = codeUnits + } + } +} + +extension Unicode.DefaultScalarView : Sequence { + struct Iterator { + var parsing: Unicode.ParsingIterator< + CodeUnits.Iterator, Encoding, Encoding.ForwardDecoder + > + } + + func makeIterator() -> Iterator { + return Iterator( + parsing: Unicode.ParsingIterator( + codeUnits: codeUnits.makeIterator(), + decoder: Encoding.ForwardDecoder() + )) + } +} + +extension Unicode.DefaultScalarView.Iterator : IteratorProtocol, Sequence { + mutating func next() -> UnicodeScalar? { + return parsing.next().map { + Encoding.ForwardDecoder.decodeOne($0) + } + } +} + +extension Unicode.DefaultScalarView { + struct Index { + var codeUnitIndex: CodeUnits.Index + var scalar: UnicodeScalar + var stride: UInt8 + } +} + +extension Unicode.DefaultScalarView.Index : Comparable { + @inline(__always) + public static func < ( + lhs: Unicode.DefaultScalarView.Index, + rhs: Unicode.DefaultScalarView.Index + ) -> Bool { + return lhs.codeUnitIndex < rhs.codeUnitIndex + } + + @inline(__always) + public static func == ( + lhs: Unicode.DefaultScalarView.Index, + rhs: Unicode.DefaultScalarView.Index + ) -> Bool { + return lhs.codeUnitIndex == rhs.codeUnitIndex + } +} + +extension Unicode.DefaultScalarView : Collection { + public var startIndex: Index { + @inline(__always) + get { + return index( + after: Index( + codeUnitIndex: codeUnits.startIndex, + scalar: UnicodeScalar(_unchecked: 0), + stride: 0) + ) + } + } + + public var endIndex: Index { + @inline(__always) + get { + return Index( + codeUnitIndex: codeUnits.endIndex, + scalar: UnicodeScalar(_unchecked: 0), + stride: 0) + } + } + + public subscript(i: Index) -> UnicodeScalar { + @inline(__always) get { return i.scalar } + } + + @inline(__always) + public func index(after i: Index) -> Index { + let nextPosition = codeUnits.index( + i.codeUnitIndex, offsetBy: numericCast(i.stride)) + var i = IndexingIterator( + _elements: codeUnits, _position: nextPosition + ) + var d = Encoding.ForwardDecoder() + switch d.parseOne(&i) { + case .valid(let scalarContent): + return Index( + codeUnitIndex: nextPosition, + scalar: Encoding.ForwardDecoder.decodeOne(scalarContent), + stride: numericCast(scalarContent.count)) + case .invalid(let stride): + return Index( + codeUnitIndex: nextPosition, + scalar: UnicodeScalar(_unchecked: 0xfffd), + stride: numericCast(stride)) + case .emptyInput: + return endIndex + } + } +} + +// This should go in the standard library; see +// https://github.com/apple/swift/pull/9074 and +// https://bugs.swift.org/browse/SR-4721 +@_fixed_layout +public struct ReverseIndexingIterator< + Elements : BidirectionalCollection +> : IteratorProtocol, Sequence { + + @_inlineable + @inline(__always) + /// Creates an iterator over the given collection. + public /// @testable + init(_elements: Elements, _position: Elements.Index) { + self._elements = _elements + self._position = _position + } + + @_inlineable + @inline(__always) + public mutating func next() -> Elements._Element? { + guard _fastPath(_position != _elements.startIndex) else { return nil } + _position = _elements.index(before: _position) + return _elements[_position] + } + + @_versioned + internal let _elements: Elements + @_versioned + internal var _position: Elements.Index +} + +extension Unicode.DefaultScalarView : BidirectionalCollection { + @inline(__always) + public func index(before i: Index) -> Index { + var d = Encoding.ReverseDecoder() + + var more = ReverseIndexingIterator( + _elements: codeUnits, _position: i.codeUnitIndex) + + switch d.parseOne(&more) { + case .valid(let scalarContent): + let d: CodeUnits.IndexDistance = -numericCast(scalarContent.count) + return Index( + codeUnitIndex: codeUnits.index(i.codeUnitIndex, offsetBy: d), + scalar: Encoding.ReverseDecoder.decodeOne(scalarContent), + stride: numericCast(scalarContent.count)) + case .invalid(let stride): + let d: CodeUnits.IndexDistance = -numericCast(stride) + return Index( + codeUnitIndex: codeUnits.index(i.codeUnitIndex, offsetBy: d) , + scalar: UnicodeScalar(_unchecked: 0xfffd), + stride: numericCast(stride)) + case .emptyInput: fatalError("index out of bounds.") + } + } +} + +public protocol UnicodeEncoding { + associatedtype CodeUnit + + associatedtype EncodedScalar + where CodeUnit == EncodedScalar.Iterator.Element + + static var encodedReplacementScalar : EncodedScalar { get } + static func decode(_ content: EncodedScalar) -> UnicodeScalar + + associatedtype ForwardDecoder : UnicodeDecoder + where EncodedScalar == ForwardDecoder.EncodedScalar + + associatedtype ReverseDecoder : UnicodeDecoder + where EncodedScalar == ReverseDecoder.EncodedScalar +} + +internal protocol _UTFEncoding : UnicodeEncoding { + static func _isScalar(_: CodeUnit) -> Bool +} + +public protocol _UTFDecoderBase : UnicodeDecoder { + + associatedtype Buffer : RangeReplaceableCollection = EncodedScalar + var buffer: Buffer { get set } + + associatedtype BufferStorage : UnsignedInteger, FixedWidthInteger = UInt32 +} + +public protocol _UTFDecoder : _UTFDecoderBase +where Buffer == _UIntBuffer, Buffer == EncodedScalar { + static func _isScalar(_: CodeUnit) -> Bool + func _parseMultipleCodeUnits() -> Unicode.ParseResult +} + +extension _UTFEncoding { + public mutating func parseScalar( + from input: inout I, with decoder: inout Decoder + ) -> Unicode.ParseResult + where I.Element == CodeUnit { + + // Bufferless single-scalar fastpath. + if _fastPath(buffer.isEmpty) { + guard let codeUnit = input.next() else { return .emptyInput } + // ASCII, return immediately. + if Self._isScalar(codeUnit) { + return ( + EncodedScalar(containing: codeUnit), + consumedCodeUnits: 1, isValid: true) + } + // Non-ASCII, proceed to buffering mode. + buffer.append(codeUnit) + } else if Self._isScalar(CodeUnit(extendingOrTruncating: buffer._storage)) { + // ASCII in buffer. We don't refill the buffer so we can return + // to bufferless mode once we've exhausted it. + let codeUnit = CodeUnit(extendingOrTruncating: buffer._storage) + buffer.remove(at: buffer.startIndex) + return ( + EncodedScalar(containing: codeUnit), + consumedCodeUnits: 1, isValid: true) + } + // Buffering mode. + // Fill buffer back to 4 bytes (or as many as are left in the iterator). + _sanityCheck(buffer._bitCount < BufferStorage.bitWidth) + repeat { + if let codeUnit = input.next() { + buffer.append(codeUnit) + } else { + if buffer.isEmpty { return .emptyInput } + break // We still have some bytes left in our buffer. + } + } while buffer._bitCount < BufferStorage.bitWidth + + // Find one unicode scalar. + return _parseMultipleCodeUnits() + } +} + +//===----------------------------------------------------------------------===// +//===--- UTF8 Decoders ----------------------------------------------------===// +//===----------------------------------------------------------------------===// + +public protocol _UTF8Decoder : _UTFDecoder {} + +extension _UTF8Decoder { + public static func _isScalar(_ x: CodeUnit) -> Bool { return x & 0x80 == 0 } +} + +extension Unicode.UTF8 : UnicodeEncoding { + public typealias EncodedScalar = _UIntBuffer + public static var encodedReplacementScalar : EncodedScalar { + return EncodedScalar(_storage: 0xbdbfef, _bitCount: 24) + } + + public struct ForwardDecoder { + public typealias Buffer = _UIntBuffer + public typealias EncodedScalar = _UIntBuffer + public init() { } + public var buffer = Buffer() + } + + public struct ReverseDecoder { + public typealias Buffer = _UIntBuffer + public typealias EncodedScalar = _UIntBuffer + public init() { } + public var buffer = Buffer() + } + + public static func decode(_ source: EncodedScalar) -> UnicodeScalar { + let bits = source._storage + switch source._bitCount { + case 8: + return UnicodeScalar(_unchecked: bits) + case 16: + var value = (bits & 0b0_______________________11_1111__0000_0000) &>> 8 + value |= (bits & 0b0________________________________0001_1111) &<< 6 + return UnicodeScalar(_unchecked: value) + case 24: + var value = (bits & 0b0____________11_1111__0000_0000__0000_0000) &>> 16 + value |= (bits & 0b0_______________________11_1111__0000_0000) &>> 2 + value |= (bits & 0b0________________________________0000_1111) &<< 12 + return UnicodeScalar(_unchecked: value) + default: + _sanityCheck(source.count == 4) + var value = (bits & 0b0_11_1111__0000_0000__0000_0000__0000_0000) &>> 24 + value |= (bits & 0b0____________11_1111__0000_0000__0000_0000) &>> 10 + value |= (bits & 0b0_______________________11_1111__0000_0000) &<< 4 + value |= (bits & 0b0________________________________0000_0111) &<< 18 + return UnicodeScalar(_unchecked: value) + } + } +} + +extension Unicode.UTF8.ReverseDecoder : _UTF8Decoder { + public typealias CodeUnit = UInt8 + + @inline(__always) + @_versioned + internal mutating func _consumeCodeUnits(_ n: UInt8) -> EncodedScalar { + let s = buffer._storage + let bitCount = n &* UInt8(CodeUnit.bitWidth) + buffer._storage >>= bitCount + buffer._bitCount -= bitCount + return EncodedScalar( + _storage: s.byteSwapped >> (type(of: s).bitWidth - bitCount), + _bitCount: bitCount) + } + + @inline(__always) + @_versioned + internal mutating func _consumeValidCodeUnits( + _ n: UInt8 + ) -> Unicode.ParseResult { + return ParseResult( + _consumeCodeUnits(n), consumedCodeUnits: n, isValid: true) + } + + @inline(__always) + @_versioned + internal mutating func _consumeInvalidCodeUnits( + _ n: UInt8 + ) -> Unicode.ParseResult { + _ = _consumeCodeUnits(n) + return ParseResult( + UTF8.encodedReplacementScalar, consumedCodeUnits: n, isValid: false) + } + + public // @testable + func _parseMultipleCodeUnits() -> Unicode.ParseResult { + _sanityCheck(buffer._storage & 0x80 != 0) // this case handled elsewhere + + if buffer._storage & 0b0__1110_0000__1100_0000 + == 0b0__1100_0000__1000_0000 { + // 2-byte sequence. Top 4 bits of decoded result must be nonzero + let top4Bits = buffer._storage & 0b0__0001_1110__0000_0000 + if _fastPath(top4Bits != 0) { + return _consumeValidCodeUnits(2) + } + } + else if buffer._storage & 0b0__1111_0000__1100_0000__1100_0000 + == 0b0__1110_0000__1000_0000__1000_0000 { + // 3-byte sequence. The top 5 bits of the decoded result must be nonzero + // and not a surrogate + let top5Bits = buffer._storage & 0b0__1111__0010_0000__0000_0000 + if _fastPath( + top5Bits != 0 && top5Bits != 0b0__1101__0010_0000__0000_0000) { + return _consumeValidCodeUnits(3) + } + } + else if buffer._storage & 0b0__1111_1000__1100_0000__1100_0000__1100_0000 + == 0b0__1111_0000__1000_0000__1000_0000__1000_0000 { + // Make sure the top 5 bits of the decoded result would be in range + let top5bits = buffer._storage + & 0b0__0111__0011_0000__0000_0000__0000_0000 + if _fastPath( + top5bits != 0 + && top5bits <= 0b0__0100__0000_0000__0000_0000__0000_0000 + ) { + return _consumeValidCodeUnits(4) + } + } + return _parseInvalid() + } + + @inline(never) + mutating func _parseInvalid() -> Unicode.ParseResult { + if buffer._storage & 0b0__1111_0000__1100_0000 + == 0b0__1110_0000__1000_0000 { + // 2-byte prefix of 3-byte sequence. The top 5 bits of the decoded result + // must be nonzero and not a surrogate + let top5Bits = buffer._storage & 0b0__1111__0010_0000 + if top5Bits != 0 && top5Bits != 0b0__1101__0010_0000 { + return invalid(codeUnitCount: 2) + } + } + else if buffer._storage & 0b0__1111_1000__1100_0000 + == 0b0__1111_0000__1000_0000 + { + // 2-byte prefix of 4-byte sequence + // Make sure the top 5 bits of the decoded result would be in range + let top5bits = buffer._storage & 0b0__0111__0011_0000 + if top5bits != 0 && top5bits <= 0b0__0100__0000_0000 { + return invalid(codeUnitCount: 2) + } + } + else if buffer._storage & 0b0__1111_1000__1100_0000__1100_0000 + == 0b0__1111_0000__1000_0000__1000_0000 { + // 3-byte prefix of 4-byte sequence + // Make sure the top 5 bits of the decoded result would be in range + let top5bits = buffer._storage & 0b0__0111__0011_0000__0000_0000 + if top5bits != 0 && top5bits <= 0b0__0100__0000_0000__0000_0000 { + return invalid(codeUnitCount: 3) + } + } + return invalid(codeUnitCount: 1) + } +} + +extension Unicode.UTF8.ForwardDecoder : _UTF8Decoder { + public typealias CodeUnit = UInt8 + + @inline(__always) + @_versioned + internal mutating func _consumeCodeUnits(_ n: UInt8) -> EncodedScalar { + let s = buffer._storage + let bitCount = n &* UInt8(CodeUnit.bitWidth) + buffer._storage >>= bitCount + buffer._bitCount -= bitCount + return EncodedScalar(_storage: s, _bitCount: bitCount) + } + + @inline(__always) + @_versioned + internal mutating func _consumeValidCodeUnits( + _ n: UInt8 + ) -> Unicode.ParseResult { + return ParseResult( + _consumeCodeUnits(codeUnitCount, consumedCodeUnits: n, isValid: true)) + } + + @inline(__always) + @_versioned + internal func _consumeInvalidCodeUnits( + codeUnitCount n: UInt8 + ) -> Unicode.ParseResult { + _ = _consumeCodeUnits(n) + return ParseResult( + UTF8.encodedReplacementScalar, consumedCodeUnits: n, isValid: false) + } + + public // @testable + func _parseMultipleCodeUnits() -> Unicode.ParseResult { + _sanityCheck(buffer._storage & 0x80 != 0) // this case handled elsewhere + + if buffer._storage & 0b0__1100_0000__1110_0000 + == 0b0__1000_0000__1100_0000 { + // 2-byte sequence. At least one of the top 4 bits of the decoded result + // must be nonzero. + if _fastPath(buffer._storage & 0b0_0001_1110 != 0) { + return _consumeValidCodeUnits(2) + } + } + else if buffer._storage & 0b0__1100_0000__1100_0000__1111_0000 + == 0b0__1000_0000__1000_0000__1110_0000 { + // 3-byte sequence. The top 5 bits of the decoded result must be nonzero + // and not a surrogate + let top5Bits = buffer._storage & 0b0___0010_0000__0000_1111 + if _fastPath(top5Bits != 0 && top5Bits != 0b0___0010_0000__0000_1101) { + return _consumeValidCodeUnits(3) + } + } + else if buffer._storage & 0b0__1100_0000__1100_0000__1100_0000__1111_1000 + == 0b0__1000_0000__1000_0000__1000_0000__1111_0000 { + // 4-byte sequence. The top 5 bits of the decoded result must be nonzero + // and no greater than 0b0__0100_0000 + let top5bits = UInt16(buffer._storage & 0b0__0011_0000__0000_0111) + if _fastPath( + top5bits != 0 && top5bits.byteSwapped <= 0b0__0000_0100__0000_0000 + ) { + return _consumeValidCodeUnits(4) + } + } + return _parseInvalid() + } + + @inline(never) + mutating func _parseInvalid() -> Unicode.ParseResult { + + if buffer._storage & 0b0__1100_0000__1111_0000 + == 0b0__1000_0000__1110_0000 { + // 2-byte prefix of 3-byte sequence. The top 5 bits of the decoded result + // must be nonzero and not a surrogate + let top5Bits = buffer._storage & 0b0__0010_0000__0000_1111 + if top5Bits != 0 && top5Bits != 0b0__0010_0000__0000_1101 { + return _consumeInvalidCodeUnits(2) + } + } + else if buffer._storage & 0b0__1100_0000__1111_1000 + == 0b0__1000_0000__1111_0000 + { + // Prefix of 4-byte sequence. The top 5 bits of the decoded result + // must be nonzero and no greater than 0b0__0100_0000 + let top5bits = UInt16(buffer._storage & 0b0__0011_0000__0000_0111) + if top5bits != 0 && top5bits.byteSwapped <= 0b0__0000_0100__0000_0000 { + return _consumeInvalidCodeUnits( + buffer._storage & 0b0__1100_0000__0000_0000__0000_0000 + == 0b0__1000_0000__0000_0000__0000_0000 ? 3 : 2) + } + } + return 1 + } +} + +//===----------------------------------------------------------------------===// +//===--- UTF-16 Decoders --------------------------------------------------===// +//===----------------------------------------------------------------------===// + +public protocol _UTF16Decoder : _UTFDecoder where CodeUnit == UTF16.CodeUnit { + var buffer: Buffer { get set } + static var _surrogatePattern : UInt32 { get } +} + +extension _UTF16Decoder { + public static func _isScalar(_ x: CodeUnit) -> Bool { + return x & 0xf800 != 0xd800 + } + + internal mutating func _consume(bitCount: UInt8) -> EncodedScalar { + _sanityCheck(bitCount == 16) + let s = buffer._storage + buffer._storage = 0 + buffer._bitCount = 0 + return EncodedScalar(_storage: s, _bitCount: bitCount) + } + + public // @testable + func _parseMultipleCodeUnits() -> (isValid: Bool, bitCount: UInt8) { + _sanityCheck( // this case handled elsewhere + !Self._isScalar(UInt16(extendingOrTruncating: buffer._storage))) + + if _fastPath(buffer._storage & 0xFC00_FC00 == Self._surrogatePattern) { + return (true, 2*16) + } + return (false, 1*16) + } +} + +extension Unicode.UTF16 : UnicodeEncoding { + public typealias EncodedScalar = _UIntBuffer + public static var encodedReplacementScalar : EncodedScalar { + return EncodedScalar(_storage: 0xFFFD, _bitCount: 16) + } + + public struct ForwardDecoder { + public typealias Buffer = _UIntBuffer + public init() { buffer = Buffer() } + public var buffer: Buffer + } + + public struct ReverseDecoder { + public typealias Buffer = _UIntBuffer + public init() { buffer = Buffer() } + public var buffer: Buffer + } + + public static func decode(_ source: EncodedScalar) -> UnicodeScalar { + let bits = source._storage + if _fastPath(source._bitCount == 16) { + return UnicodeScalar(_unchecked: bits & 0xffff) + } + _sanityCheck(source._bitCount == 32) + let value = 0x10000 + (bits >> 16 & 0x03ff | (bits & 0x03ff) << 10) + return UnicodeScalar(_unchecked: value) + } +} + +extension UTF16.ReverseDecoder : _UTF16Decoder { + public typealias CodeUnit = UInt16 + public typealias EncodedScalar = Buffer + + public static var _surrogatePattern : UInt32 { return 0xD800_DC00 } +} + +extension Unicode.UTF16.ForwardDecoder : _UTF16Decoder { + public typealias CodeUnit = UInt16 + public typealias EncodedScalar = Buffer + + public static var _surrogatePattern : UInt32 { return 0xDC00_D800 } +} + +#if !BENCHMARK +//===--- testing ----------------------------------------------------------===// +import StdlibUnittest +import SwiftPrivate + +func checkDecodeUTF( + _ codec: Codec.Type, _ expectedHead: [UInt32], + _ expectedRepairedTail: [UInt32], _ utfStr: [Codec.CodeUnit] +) -> AssertionResult { + var decoded = [UInt32]() + var expected = expectedHead + func output(_ scalar: UInt32) { decoded.append(scalar) } + func output1(_ scalar: UnicodeScalar) { decoded.append(scalar.value) } + + var result = assertionSuccess() + + func check(_ expected: C, _ description: String) + where C.Iterator.Element == UInt32 + { + if !expected.elementsEqual(decoded) { + if result.description == "" { result = assertionFailure() } + result = result.withDescription(" [\(description)]\n") + .withDescription("expected: \(asHex(expectedHead))\n") + .withDescription("actual: \(asHex(decoded))") + } + decoded.removeAll(keepingCapacity: true) + } + + //===--- Tests without repairs ------------------------------------------===// + do { + let iterator = utfStr.makeIterator() + _ = transcode( + iterator, from: codec, to: UTF32.self, + stoppingOnError: true, into: output) + } + check(expected, "legacy, repairing: false") + + do { + var iterator = utfStr.makeIterator() + let errorCount = Codec.ForwardDecoder.decode( + &iterator, repairingIllFormedSequences: false, into: output1) + expectEqual(expectedRepairedTail.isEmpty ? 0 : 1, errorCount) + } + check(expected, "forward, repairing: false") + + do { + var iterator = utfStr.reversed().makeIterator() + let errorCount = Codec.ReverseDecoder.decode( + &iterator, repairingIllFormedSequences: false, into: output1) + if expectedRepairedTail.isEmpty { + expectEqual(0, errorCount) + check(expected.reversed(), "reverse, repairing: false") + } + else { + expectEqual(1, errorCount) + let x = (expected + expectedRepairedTail).reversed() + expectTrue( + x.starts(with: decoded), + "reverse, repairing: false\n\t\(Array(x)) does not start with \(decoded)") + decoded.removeAll(keepingCapacity: true) + } + } + + //===--- Tests with repairs ------------------------------------------===// + expected += expectedRepairedTail + do { + let iterator = utfStr.makeIterator() + _ = transcode(iterator, from: codec, to: UTF32.self, + stoppingOnError: false, into: output) + } + check(expected, "legacy, repairing: true") + do { + var iterator = utfStr.makeIterator() + let errorCount = Codec.ForwardDecoder.decode( + &iterator, repairingIllFormedSequences: true, into: output1) + + if expectedRepairedTail.isEmpty { expectEqual(0, errorCount) } + else { expectNotEqual(0, errorCount) } + } + check(expected, "forward, repairing: true") + do { + var iterator = utfStr.reversed().makeIterator() + let errorCount = Codec.ReverseDecoder.decode( + &iterator, repairingIllFormedSequences: true, into: output1) + if expectedRepairedTail.isEmpty { expectEqual(0, errorCount) } + else { expectNotEqual(0, errorCount) } + } + check(expected.reversed(), "reverse, repairing: true") + + let scalars = Unicode.DefaultScalarView(utfStr, fromEncoding: Codec.self) + expectEqualSequence(expected, scalars.map { $0.value }) + expectEqualSequence( + expected.reversed(), + scalars.reversed().map { $0.value }) + + do { + var x = scalars.makeIterator() + var j = scalars.startIndex + while (j != scalars.endIndex) { + expectEqual(x.next()!, scalars[j]) + j = scalars.index(after: j) + } + expectNil(x.next()) + } + return result +} + +func checkDecodeUTF8( + _ expectedHead: [UInt32], + _ expectedRepairedTail: [UInt32], _ utf8Str: [UInt8] +) -> AssertionResult { + return checkDecodeUTF(UTF8.self, expectedHead, expectedRepairedTail, utf8Str) +} + +func checkDecodeUTF16( + _ expectedHead: [UInt32], + _ expectedRepairedTail: [UInt32], _ utf16Str: [UInt16] +) -> AssertionResult { + return checkDecodeUTF(UTF16.self, expectedHead, expectedRepairedTail, + utf16Str) +} + +/* +func checkDecodeUTF32( + _ expectedHead: [UInt32], + _ expectedRepairedTail: [UInt32], _ utf32Str: [UInt32] +) -> AssertionResult { + return checkDecodeUTF(UTF32.self, expectedHead, expectedRepairedTail, + utf32Str) +} +*/ + +func checkEncodeUTF8(_ expected: [UInt8], + _ scalars: [UInt32]) -> AssertionResult { + var encoded = [UInt8]() + let output: (UInt8) -> Void = { encoded.append($0) } + let iterator = scalars.makeIterator() + let hadError = transcode( + iterator, + from: UTF32.self, + to: UTF8.self, + stoppingOnError: true, + into: output) + expectFalse(hadError) + if expected != encoded { + return assertionFailure() + .withDescription("\n") + .withDescription("expected: \(asHex(expected))\n") + .withDescription("actual: \(asHex(encoded))") + } + + return assertionSuccess() +} + +var UTF8Decoder = TestSuite("UTF8Decoder") + +//===----------------------------------------------------------------------===// +public struct UTFTest { + public struct Flags : OptionSet { + public let rawValue: Int + + public init(rawValue: Int) { + self.rawValue = rawValue + } + + public static let utf8IsInvalid = Flags(rawValue: 1 << 0) + public static let utf16IsInvalid = Flags(rawValue: 1 << 1) + } + + public let string: String + public let utf8: [UInt8] + public let utf16: [UInt16] + public let unicodeScalars: [UnicodeScalar] + public let unicodeScalarsRepairedTail: [UnicodeScalar] + public let flags: Flags + public let loc: SourceLoc + + public var utf32: [UInt32] { + return unicodeScalars.map(UInt32.init) + } + + public var utf32RepairedTail: [UInt32] { + return unicodeScalarsRepairedTail.map(UInt32.init) + } + + public init( + string: String, + utf8: [UInt8], + utf16: [UInt16], + scalars: [UInt32], + scalarsRepairedTail: [UInt32] = [], + flags: Flags = [], + file: String = #file, line: UInt = #line + ) { + self.string = string + self.utf8 = utf8 + self.utf16 = utf16 + self.unicodeScalars = scalars.map { UnicodeScalar($0)! } + self.unicodeScalarsRepairedTail = + scalarsRepairedTail.map { UnicodeScalar($0)! } + self.flags = flags + self.loc = SourceLoc(file, line, comment: "test data") + } +} + +public var utfTests: [UTFTest] = [] + // + // Empty sequence. + // + +utfTests.append( + UTFTest( + string: "", + utf8: [], + utf16: [], + scalars: [])) + + // + // 1-byte sequences. + // + + // U+0000 NULL +utfTests.append( + UTFTest( + string: "\u{0000}", + utf8: [ 0x00 ], + utf16: [ 0x00 ], + scalars: [ 0x00 ])) + + // U+0041 LATIN CAPITAL LETTER A +utfTests.append( + UTFTest( + string: "A", + utf8: [ 0x41 ], + utf16: [ 0x41 ], + scalars: [ 0x41 ])) + + // U+0041 LATIN CAPITAL LETTER A + // U+0042 LATIN CAPITAL LETTER B +utfTests.append( + UTFTest( + string: "AB", + utf8: [ 0x41, 0x42 ], + utf16: [ 0x41, 0x42 ], + scalars: [ 0x41, 0x42 ])) + + // U+0061 LATIN SMALL LETTER A + // U+0062 LATIN SMALL LETTER B + // U+0063 LATIN SMALL LETTER C +utfTests.append( + UTFTest( + string: "ABC", + utf8: [ 0x41, 0x42, 0x43 ], + utf16: [ 0x41, 0x42, 0x43 ], + scalars: [ 0x41, 0x42, 0x43 ])) + + // U+0000 NULL + // U+0041 LATIN CAPITAL LETTER A + // U+0042 LATIN CAPITAL LETTER B + // U+0000 NULL +utfTests.append( + UTFTest( + string: "\u{0000}AB\u{0000}", + utf8: [ 0x00, 0x41, 0x42, 0x00 ], + utf16: [ 0x00, 0x41, 0x42, 0x00 ], + scalars: [ 0x00, 0x41, 0x42, 0x00 ])) + + // U+007F DELETE +utfTests.append( + UTFTest( + string: "\u{007F}", + utf8: [ 0x7F ], + utf16: [ 0x7F ], + scalars: [ 0x7F ])) + + // + // 2-byte sequences. + // + + // U+0283 LATIN SMALL LETTER ESH +utfTests.append( + UTFTest( + string: "\u{0283}", + utf8: [ 0xCA, 0x83 ], + utf16: [ 0x0283 ], + scalars: [ 0x0283 ])) + + // U+03BA GREEK SMALL LETTER KAPPA + // U+1F79 GREEK SMALL LETTER OMICRON WITH OXIA + // U+03C3 GREEK SMALL LETTER SIGMA + // U+03BC GREEK SMALL LETTER MU + // U+03B5 GREEK SMALL LETTER EPSILON +utfTests.append( + UTFTest( + string: "\u{03BA}\u{1F79}\u{03C3}\u{03BC}\u{03B5}", + utf8: [ 0xCE, 0xBA, 0xE1, 0xBD, 0xB9, 0xCF, 0x83, 0xCE, 0xBC, 0xCE, 0xB5 ], + utf16: [ 0x03BA, 0x1F79, 0x03C3, 0x03BC, 0x03B5 ], + scalars: [ 0x03BA, 0x1F79, 0x03C3, 0x03BC, 0x03B5 ])) + + // U+0430 CYRILLIC SMALL LETTER A + // U+0431 CYRILLIC SMALL LETTER BE + // U+0432 CYRILLIC SMALL LETTER VE +utfTests.append( + UTFTest( + string: "\u{0430}\u{0431}\u{0432}", + utf8: [ 0xD0, 0xB0, 0xD0, 0xB1, 0xD0, 0xB2 ], + utf16: [ 0x0430, 0x0431, 0x0432 ], + scalars: [ 0x0430, 0x0431, 0x0432 ])) + + // + // 3-byte sequences. + // + + // U+4F8B CJK UNIFIED IDEOGRAPH-4F8B + // U+6587 CJK UNIFIED IDEOGRAPH-6587 +utfTests.append( + UTFTest( + string: "\u{4F8b}\u{6587}", + utf8: [ 0xE4, 0xBE, 0x8B, 0xE6, 0x96, 0x87 ], + utf16: [ 0x4F8B, 0x6587 ], + scalars: [ 0x4F8B, 0x6587 ])) + + // U+D55C HANGUL SYLLABLE HAN + // U+AE00 HANGUL SYLLABLE GEUL +utfTests.append( + UTFTest( + string: "\u{d55c}\u{ae00}", + utf8: [ 0xED, 0x95, 0x9C, 0xEA, 0xB8, 0x80 ], + utf16: [ 0xD55C, 0xAE00 ], + scalars: [ 0xD55C, 0xAE00 ])) + + // U+1112 HANGUL CHOSEONG HIEUH + // U+1161 HANGUL JUNGSEONG A + // U+11AB HANGUL JONGSEONG NIEUN + // U+1100 HANGUL CHOSEONG KIYEOK + // U+1173 HANGUL JUNGSEONG EU + // U+11AF HANGUL JONGSEONG RIEUL +utfTests.append( + UTFTest( + string: "\u{1112}\u{1161}\u{11ab}\u{1100}\u{1173}\u{11af}", + utf8: + [ 0xE1, 0x84, 0x92, 0xE1, 0x85, 0xA1, 0xE1, 0x86, 0xAB, + 0xE1, 0x84, 0x80, 0xE1, 0x85, 0xB3, 0xE1, 0x86, 0xAF ], + utf16: [ 0x1112, 0x1161, 0x11AB, 0x1100, 0x1173, 0x11AF ], + scalars: [ 0x1112, 0x1161, 0x11AB, 0x1100, 0x1173, 0x11AF ])) + + // U+3042 HIRAGANA LETTER A + // U+3044 HIRAGANA LETTER I + // U+3046 HIRAGANA LETTER U + // U+3048 HIRAGANA LETTER E + // U+304A HIRAGANA LETTER O +utfTests.append( + UTFTest( + string: "\u{3042}\u{3044}\u{3046}\u{3048}\u{304a}", + utf8: + [ 0xE3, 0x81, 0x82, 0xE3, 0x81, 0x84, 0xE3, 0x81, 0x86, + 0xE3, 0x81, 0x88, 0xE3, 0x81, 0x8A ], + utf16: [ 0x3042, 0x3044, 0x3046, 0x3048, 0x304A ], + scalars: [ 0x3042, 0x3044, 0x3046, 0x3048, 0x304A ])) + + // U+D7FF (unassigned) +utfTests.append( + UTFTest( + string: "\u{D7FF}", + utf8: [ 0xED, 0x9F, 0xBF ], + utf16: [ 0xD7FF ], + scalars: [ 0xD7FF ])) + + // U+E000 (private use) +utfTests.append( + UTFTest( + string: "\u{E000}", + utf8: [ 0xEE, 0x80, 0x80 ], + utf16: [ 0xE000 ], + scalars: [ 0xE000 ])) + + // U+FFFD REPLACEMENT CHARACTER +utfTests.append( + UTFTest( + string: "\u{FFFD}", + utf8: [ 0xEF, 0xBF, 0xBD ], + utf16: [ 0xFFFD ], + scalars: [ 0xFFFD ])) + + // U+FFFF (noncharacter) +utfTests.append( + UTFTest( + string: "\u{FFFF}", + utf8: [ 0xEF, 0xBF, 0xBF ], + utf16: [ 0xFFFF ], + scalars: [ 0xFFFF ])) + + // + // 4-byte sequences. + // + + // U+1F425 FRONT-FACING BABY CHICK +utfTests.append( + UTFTest( + string: "\u{1F425}", + utf8: [ 0xF0, 0x9F, 0x90, 0xA5 ], + utf16: [ 0xD83D, 0xDC25 ], + scalars: [ 0x0001_F425 ])) + + // U+0041 LATIN CAPITAL LETTER A + // U+1F425 FRONT-FACING BABY CHICK +utfTests.append( + UTFTest( + string: "A\u{1F425}", + utf8: [ 0x41, 0xF0, 0x9F, 0x90, 0xA5 ], + utf16: [ 0x41, 0xD83D, 0xDC25 ], + scalars: [ 0x41, 0x0001_F425 ])) + + // U+0041 LATIN CAPITAL LETTER A + // U+0042 LATIN CAPITAL LETTER B + // U+1F425 FRONT-FACING BABY CHICK +utfTests.append( + UTFTest( + string: "AB\u{1F425}", + utf8: [ 0x41, 0x42, 0xF0, 0x9F, 0x90, 0xA5 ], + utf16: [ 0x41, 0x42, 0xD83D, 0xDC25 ], + scalars: [ 0x41, 0x42, 0x0001_F425 ])) + + // U+0041 LATIN CAPITAL LETTER A + // U+0042 LATIN CAPITAL LETTER B + // U+0043 LATIN CAPITAL LETTER C + // U+1F425 FRONT-FACING BABY CHICK +utfTests.append( + UTFTest( + string: "ABC\u{1F425}", + utf8: [ 0x41, 0x42, 0x43, 0xF0, 0x9F, 0x90, 0xA5 ], + utf16: [ 0x41, 0x42, 0x43, 0xD83D, 0xDC25 ], + scalars: [ 0x41, 0x42, 0x43, 0x0001_F425 ])) + + // U+0041 LATIN CAPITAL LETTER A + // U+0042 LATIN CAPITAL LETTER B + // U+0043 LATIN CAPITAL LETTER C + // U+0044 LATIN CAPITAL LETTER D + // U+1F425 FRONT-FACING BABY CHICK +utfTests.append( + UTFTest( + string: "ABCD\u{1F425}", + utf8: [ 0x41, 0x42, 0x43, 0x44, 0xF0, 0x9F, 0x90, 0xA5 ], + utf16: [ 0x41, 0x42, 0x43, 0x44, 0xD83D, 0xDC25 ], + scalars: [ 0x41, 0x42, 0x43, 0x44, 0x0001_F425 ])) + + // U+0041 LATIN CAPITAL LETTER A + // U+0042 LATIN CAPITAL LETTER B + // U+0043 LATIN CAPITAL LETTER C + // U+0044 LATIN CAPITAL LETTER D + // U+0045 LATIN CAPITAL LETTER E + // U+1F425 FRONT-FACING BABY CHICK +utfTests.append( + UTFTest( + string: "ABCDE\u{1F425}", + utf8: [ 0x41, 0x42, 0x43, 0x44, 0x45, 0xF0, 0x9F, 0x90, 0xA5 ], + utf16: [ 0x41, 0x42, 0x43, 0x44, 0x45, 0xD83D, 0xDC25 ], + scalars: [ 0x41, 0x42, 0x43, 0x44, 0x45, 0x0001_F425 ])) + + // U+0041 LATIN CAPITAL LETTER A + // U+0042 LATIN CAPITAL LETTER B + // U+0043 LATIN CAPITAL LETTER C + // U+0044 LATIN CAPITAL LETTER D + // U+0045 LATIN CAPITAL LETTER E + // U+0046 LATIN CAPITAL LETTER F + // U+1F425 FRONT-FACING BABY CHICK +utfTests.append( + UTFTest( + string: "ABCDEF\u{1F425}", + utf8: [ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0xF0, 0x9F, 0x90, 0xA5 ], + utf16: [ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0xD83D, 0xDC25 ], + scalars: [ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x0001_F425 ])) + + // U+0041 LATIN CAPITAL LETTER A + // U+0042 LATIN CAPITAL LETTER B + // U+0043 LATIN CAPITAL LETTER C + // U+0044 LATIN CAPITAL LETTER D + // U+0045 LATIN CAPITAL LETTER E + // U+0046 LATIN CAPITAL LETTER F + // U+0047 LATIN CAPITAL LETTER G + // U+1F425 FRONT-FACING BABY CHICK +utfTests.append( + UTFTest( + string: "ABCDEFG\u{1F425}", + utf8: [ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0xF0, 0x9F, 0x90, 0xA5 ], + utf16: [ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0xD83D, 0xDC25 ], + scalars: [ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x0001_F425 ])) + + // U+0041 LATIN CAPITAL LETTER A + // U+0042 LATIN CAPITAL LETTER B + // U+0043 LATIN CAPITAL LETTER C + // U+0044 LATIN CAPITAL LETTER D + // U+0045 LATIN CAPITAL LETTER E + // U+0046 LATIN CAPITAL LETTER F + // U+0047 LATIN CAPITAL LETTER G + // U+0048 LATIN CAPITAL LETTER H + // U+1F425 FRONT-FACING BABY CHICK +utfTests.append( + UTFTest( + string: "ABCDEFGH\u{1F425}", + utf8: + [ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0xF0, 0x9F, 0x90, 0xA5 ], + utf16: + [ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0xD83D, 0xDC25 ], + scalars: + [ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x0001_F425 ])) + + // U+0041 LATIN CAPITAL LETTER A + // U+0042 LATIN CAPITAL LETTER B + // U+0043 LATIN CAPITAL LETTER C + // U+0044 LATIN CAPITAL LETTER D + // U+0045 LATIN CAPITAL LETTER E + // U+0046 LATIN CAPITAL LETTER F + // U+0047 LATIN CAPITAL LETTER G + // U+0048 LATIN CAPITAL LETTER H + // U+0049 LATIN CAPITAL LETTER I + // U+1F425 FRONT-FACING BABY CHICK +utfTests.append( + UTFTest( + string: "ABCDEFGHI\u{1F425}", + utf8: + [ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0xF0, 0x9F, 0x90, 0xA5 ], + utf16: + [ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0xD83D, 0xDC25 ], + scalars: + [ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x0001_F425 ])) + + // U+10000 LINEAR B SYLLABLE B008 A +utfTests.append( + UTFTest( + string: "\u{10000}", + utf8: [ 0xF0, 0x90, 0x80, 0x80 ], + utf16: [ 0xD800, 0xDC00 ], + scalars: [ 0x0001_0000 ])) + + // U+10100 AEGEAN WORD SEPARATOR LINE +utfTests.append( + UTFTest( + string: "\u{10100}", + utf8: [ 0xF0, 0x90, 0x84, 0x80 ], + utf16: [ 0xD800, 0xDD00 ], + scalars: [ 0x0001_0100 ])) + + // U+103FF (unassigned) +utfTests.append( + UTFTest( + string: "\u{103FF}", + utf8: [ 0xF0, 0x90, 0x8F, 0xBF ], + utf16: [ 0xD800, 0xDFFF ], + scalars: [ 0x0001_03FF ])) + + // U+E0000 (unassigned) +utfTests.append( + UTFTest( + string: "\u{E0000}", + utf8: [ 0xF3, 0xA0, 0x80, 0x80 ], + utf16: [ 0xDB40, 0xDC00 ], + scalars: [ 0x000E_0000 ])) + + // U+E0100 VARIATION SELECTOR-17 +utfTests.append( + UTFTest( + string: "\u{E0100}", + utf8: [ 0xF3, 0xA0, 0x84, 0x80 ], + utf16: [ 0xDB40, 0xDD00 ], + scalars: [ 0x000E_0100 ])) + + // U+E03FF (unassigned) +utfTests.append( + UTFTest( + string: "\u{E03FF}", + utf8: [ 0xF3, 0xA0, 0x8F, 0xBF ], + utf16: [ 0xDB40, 0xDFFF ], + scalars: [ 0x000E_03FF ])) + + // U+10FC00 (private use) +utfTests.append( + UTFTest( + string: "\u{10FC00}", + utf8: [ 0xF4, 0x8F, 0xB0, 0x80 ], + utf16: [ 0xDBFF, 0xDC00 ], + scalars: [ 0x0010_FC00 ])) + + // U+10FD00 (private use) +utfTests.append( + UTFTest( + string: "\u{10FD00}", + utf8: [ 0xF4, 0x8F, 0xB4, 0x80 ], + utf16: [ 0xDBFF, 0xDD00 ], + scalars: [ 0x0010_FD00 ])) + + // U+10FFFF (private use, noncharacter) +utfTests.append( + UTFTest( + string: "\u{10FFFF}", + utf8: [ 0xF4, 0x8F, 0xBF, 0xBF ], + utf16: [ 0xDBFF, 0xDFFF ], + scalars: [ 0x0010_FFFF ])) +//===----------------------------------------------------------------------===// + +UTF8Decoder.test("SmokeTest").forEach(in: utfTests) { + test in + + expectTrue( + checkDecodeUTF8(test.utf32, [], test.utf8), + stackTrace: test.loc.withCurrentLoc()) + return () +} + +UTF8Decoder.test("FirstPossibleSequence") { + // + // First possible sequence of a certain length + // + + // U+0000 NULL + expectTrue(checkDecodeUTF8([ 0x0000 ], [], [ 0x00 ])) + + // U+0080 PADDING CHARACTER + expectTrue(checkDecodeUTF8([ 0x0080 ], [], [ 0xc2, 0x80 ])) + + // U+0800 SAMARITAN LETTER ALAF + expectTrue(checkDecodeUTF8( + [ 0x0800 ], [], + [ 0xe0, 0xa0, 0x80 ])) + + // U+10000 LINEAR B SYLLABLE B008 A + expectTrue(checkDecodeUTF8( + [ 0x10000 ], [], + [ 0xf0, 0x90, 0x80, 0x80 ])) + + // U+200000 (invalid) + expectTrue(checkDecodeUTF8( + [], [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xf8, 0x88, 0x80, 0x80, 0x80 ])) + + // U+4000000 (invalid) + expectTrue(checkDecodeUTF8( + [], [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xfc, 0x84, 0x80, 0x80, 0x80, 0x80 ])) +} + +UTF8Decoder.test("LastPossibleSequence") { + // + // Last possible sequence of a certain length + // + + // U+007F DELETE + expectTrue(checkDecodeUTF8([ 0x007f ], [], [ 0x7f ])) + + // U+07FF (unassigned) + expectTrue(checkDecodeUTF8([ 0x07ff ], [], [ 0xdf, 0xbf ])) + + // U+FFFF (noncharacter) + expectTrue(checkDecodeUTF8( + [ 0xffff ], [], + [ 0xef, 0xbf, 0xbf ])) + + // U+1FFFFF (invalid) + expectTrue(checkDecodeUTF8( + [], [ 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xf7, 0xbf, 0xbf, 0xbf ])) + + // U+3FFFFFF (invalid) + expectTrue(checkDecodeUTF8( + [], [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xfb, 0xbf, 0xbf, 0xbf, 0xbf ])) + + // U+7FFFFFFF (invalid) + expectTrue(checkDecodeUTF8( + [], [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xfd, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf ])) +} + +UTF8Decoder.test("CodeSpaceBoundaryConditions") { + // + // Other boundary conditions + // + + // U+D7FF (unassigned) + expectTrue(checkDecodeUTF8([ 0xd7ff ], [], [ 0xed, 0x9f, 0xbf ])) + + // U+E000 (private use) + expectTrue(checkDecodeUTF8([ 0xe000 ], [], [ 0xee, 0x80, 0x80 ])) + + // U+FFFD REPLACEMENT CHARACTER + expectTrue(checkDecodeUTF8([ 0xfffd ], [], [ 0xef, 0xbf, 0xbd ])) + + // U+10FFFF (noncharacter) + expectTrue(checkDecodeUTF8([ 0x10ffff ], [], [ 0xf4, 0x8f, 0xbf, 0xbf ])) + + // U+110000 (invalid) + expectTrue(checkDecodeUTF8( + [], [ 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xf4, 0x90, 0x80, 0x80 ])) +} + +UTF8Decoder.test("UnexpectedContinuationBytes") { + // + // Unexpected continuation bytes + // + + // A sequence of unexpected continuation bytes that don't follow a first + // byte, every byte is a maximal subpart. + + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0x80 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xbf ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0x80, 0x80 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0x80, 0xbf ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xbf, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], [ 0xfffd, 0xfffd, 0xfffd ], + [ 0x80, 0xbf, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], [ 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0x80, 0xbf, 0x80, 0xbf ])) + expectTrue(checkDecodeUTF8( + [], [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0x80, 0xbf, 0x82, 0xbf, 0xaa ])) + expectTrue(checkDecodeUTF8( + [], [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xaa, 0xb0, 0xbb, 0xbf, 0xaa, 0xa0 ])) + expectTrue(checkDecodeUTF8( + [], [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xaa, 0xb0, 0xbb, 0xbf, 0xaa, 0xa0, 0x8f ])) + + // All continuation bytes (0x80--0xbf). + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, + 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, + 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, + 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, + 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, + 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, + 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, + 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf ])) +} + +UTF8Decoder.test("LonelyStartBytes") { + // + // Lonely start bytes + // + + // Start bytes of 2-byte sequences (0xc0--0xdf). + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, + 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, + 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, + 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf ])) + + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, + 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, + 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, + 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, + 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, + 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, + 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, + 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020 ], + [ 0xc0, 0x20, 0xc1, 0x20, 0xc2, 0x20, 0xc3, 0x20, + 0xc4, 0x20, 0xc5, 0x20, 0xc6, 0x20, 0xc7, 0x20, + 0xc8, 0x20, 0xc9, 0x20, 0xca, 0x20, 0xcb, 0x20, + 0xcc, 0x20, 0xcd, 0x20, 0xce, 0x20, 0xcf, 0x20, + 0xd0, 0x20, 0xd1, 0x20, 0xd2, 0x20, 0xd3, 0x20, + 0xd4, 0x20, 0xd5, 0x20, 0xd6, 0x20, 0xd7, 0x20, + 0xd8, 0x20, 0xd9, 0x20, 0xda, 0x20, 0xdb, 0x20, + 0xdc, 0x20, 0xdd, 0x20, 0xde, 0x20, 0xdf, 0x20 ])) + + // Start bytes of 3-byte sequences (0xe0--0xef). + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, + 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef ])) + + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, + 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, + 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, + 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020 ], + [ 0xe0, 0x20, 0xe1, 0x20, 0xe2, 0x20, 0xe3, 0x20, + 0xe4, 0x20, 0xe5, 0x20, 0xe6, 0x20, 0xe7, 0x20, + 0xe8, 0x20, 0xe9, 0x20, 0xea, 0x20, 0xeb, 0x20, + 0xec, 0x20, 0xed, 0x20, 0xee, 0x20, 0xef, 0x20 ])) + + // Start bytes of 4-byte sequences (0xf0--0xf7). + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7 ])) + + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, + 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020 ], + [ 0xf0, 0x20, 0xf1, 0x20, 0xf2, 0x20, 0xf3, 0x20, + 0xf4, 0x20, 0xf5, 0x20, 0xf6, 0x20, 0xf7, 0x20 ])) + + // Start bytes of 5-byte sequences (0xf8--0xfb). + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xf8, 0xf9, 0xfa, 0xfb ])) + + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020 ], + [ 0xf8, 0x20, 0xf9, 0x20, 0xfa, 0x20, 0xfb, 0x20 ])) + + // Start bytes of 6-byte sequences (0xfc--0xfd). + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xfc, 0xfd ])) + + expectTrue(checkDecodeUTF8( + [], [ 0xfffd, 0x0020, 0xfffd, 0x0020 ], + [ 0xfc, 0x20, 0xfd, 0x20 ])) +} + +UTF8Decoder.test("InvalidStartBytes") { + // + // Other bytes (0xc0--0xc1, 0xfe--0xff). + // + + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xc0 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xc1 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xfe ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xff ])) + + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xc0, 0xc1, 0xfe, 0xff ])) + + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xfe, 0xfe, 0xff, 0xff ])) + + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xfe, 0x80, 0x80, 0x80, 0x80, 0x80 ])) + + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xff, 0x80, 0x80, 0x80, 0x80, 0x80 ])) + + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020, 0xfffd, 0x0020 ], + [ 0xc0, 0x20, 0xc1, 0x20, 0xfe, 0x20, 0xff, 0x20 ])) +} + +UTF8Decoder.test("MissingContinuationBytes") { + // + // Sequences with one continuation byte missing + // + + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xc2 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xdf ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0x0041 ], [ 0xc2, 0x41 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0x0041 ], [ 0xdf, 0x41 ])) + + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xe0, 0xa0 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xe0, 0xbf ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0x0041 ], [ 0xe0, 0xa0, 0x41 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0x0041 ], [ 0xe0, 0xbf, 0x41 ])) + + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xe1, 0x80 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xec, 0xbf ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0x0041 ], [ 0xe1, 0x80, 0x41 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0x0041 ], [ 0xec, 0xbf, 0x41 ])) + + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xed, 0x80 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xed, 0x9f ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0x0041 ], [ 0xed, 0x80, 0x41 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0x0041 ], [ 0xed, 0x9f, 0x41 ])) + + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xee, 0x80 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xef, 0xbf ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0x0041 ], [ 0xee, 0x80, 0x41 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0x0041 ], [ 0xef, 0xbf, 0x41 ])) + + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf0, 0x90, 0x80 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf0, 0xbf, 0xbf ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0x0041 ], [ 0xf0, 0x90, 0x80, 0x41 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0x0041 ], [ 0xf0, 0xbf, 0xbf, 0x41 ])) + + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf1, 0x80, 0x80 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf3, 0xbf, 0xbf ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0x0041 ], [ 0xf1, 0x80, 0x80, 0x41 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0x0041 ], [ 0xf3, 0xbf, 0xbf, 0x41 ])) + + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf4, 0x80, 0x80 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf4, 0x8f, 0xbf ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0x0041 ], [ 0xf4, 0x80, 0x80, 0x41 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0x0041 ], [ 0xf4, 0x8f, 0xbf, 0x41 ])) + + // Overlong sequences with one trailing byte missing. + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xc0 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xc1 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xe0, 0x80 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xe0, 0x9f ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xf0, 0x80, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xf0, 0x8f, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xf8, 0x80, 0x80, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xfc, 0x80, 0x80, 0x80, 0x80 ])) + + // Sequences that represent surrogates with one trailing byte missing. + // High-surrogates + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xed, 0xa0 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xed, 0xac ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xed, 0xaf ])) + // Low-surrogates + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xed, 0xb0 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xed, 0xb4 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xed, 0xbf ])) + + // Ill-formed 4-byte sequences. + // 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx + // U+1100xx (invalid) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xf4, 0x90, 0x80 ])) + // U+13FBxx (invalid) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xf4, 0xbf, 0xbf ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xf5, 0x80, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xf6, 0x80, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xf7, 0x80, 0x80 ])) + // U+1FFBxx (invalid) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xf7, 0xbf, 0xbf ])) + + // Ill-formed 5-byte sequences. + // 111110uu 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx + // U+2000xx (invalid) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xf8, 0x88, 0x80, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xf8, 0xbf, 0xbf, 0xbf ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xf9, 0x80, 0x80, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xfa, 0x80, 0x80, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xfb, 0x80, 0x80, 0x80 ])) + // U+3FFFFxx (invalid) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xfb, 0xbf, 0xbf, 0xbf ])) + + // Ill-formed 6-byte sequences. + // 1111110u 10uuuuuu 10uzzzzz 10zzzyyyy 10yyyyxx 10xxxxxx + // U+40000xx (invalid) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xfc, 0x84, 0x80, 0x80, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xfc, 0xbf, 0xbf, 0xbf, 0xbf ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xfd, 0x80, 0x80, 0x80, 0x80 ])) + // U+7FFFFFxx (invalid) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xfd, 0xbf, 0xbf, 0xbf, 0xbf ])) + + // + // Sequences with two continuation bytes missing + // + + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf0, 0x90 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf0, 0xbf ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf1, 0x80 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf3, 0xbf ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf4, 0x80 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf4, 0x8f ])) + + // Overlong sequences with two trailing byte missing. + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xe0 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xf0, 0x80 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xf0, 0x8f ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xf8, 0x80, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xfc, 0x80, 0x80, 0x80 ])) + + // Sequences that represent surrogates with two trailing bytes missing. + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xed ])) + + // Ill-formed 4-byte sequences. + // 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx + // U+110yxx (invalid) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xf4, 0x90 ])) + // U+13Fyxx (invalid) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xf4, 0xbf ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xf5, 0x80 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xf6, 0x80 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xf7, 0x80 ])) + // U+1FFyxx (invalid) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xf7, 0xbf ])) + + // Ill-formed 5-byte sequences. + // 111110uu 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx + // U+200yxx (invalid) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xf8, 0x88, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xf8, 0xbf, 0xbf ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xf9, 0x80, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xfa, 0x80, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xfb, 0x80, 0x80 ])) + // U+3FFFyxx (invalid) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xfb, 0xbf, 0xbf ])) + + // Ill-formed 6-byte sequences. + // 1111110u 10uuuuuu 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx + // U+4000yxx (invalid) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xfc, 0x84, 0x80, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xfc, 0xbf, 0xbf, 0xbf ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xfd, 0x80, 0x80, 0x80 ])) + // U+7FFFFyxx (invalid) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xfd, 0xbf, 0xbf, 0xbf ])) + + // + // Sequences with three continuation bytes missing + // + + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf0 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf1 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf2 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf3 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf4 ])) + + // Broken overlong sequences. + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf0 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xf8, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xfc, 0x80, 0x80 ])) + + // Ill-formed 4-byte sequences. + // 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx + // U+14yyxx (invalid) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf5 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf6 ])) + // U+1Cyyxx (invalid) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf7 ])) + + // Ill-formed 5-byte sequences. + // 111110uu 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx + // U+20yyxx (invalid) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xf8, 0x88 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xf8, 0xbf ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xf9, 0x80 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xfa, 0x80 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xfb, 0x80 ])) + // U+3FCyyxx (invalid) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xfb, 0xbf ])) + + // Ill-formed 6-byte sequences. + // 1111110u 10uuuuuu 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx + // U+400yyxx (invalid) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xfc, 0x84, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xfc, 0xbf, 0xbf ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xfd, 0x80, 0x80 ])) + // U+7FFCyyxx (invalid) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xfd, 0xbf, 0xbf ])) + + // + // Sequences with four continuation bytes missing + // + + // Ill-formed 5-byte sequences. + // 111110uu 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx + // U+uzyyxx (invalid) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf8 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf9 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xfa ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xfb ])) + // U+3zyyxx (invalid) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xfb ])) + + // Broken overlong sequences. + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xf8 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xfc, 0x80 ])) + + // Ill-formed 6-byte sequences. + // 1111110u 10uuuuuu 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx + // U+uzzyyxx (invalid) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xfc, 0x84 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xfc, 0xbf ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xfd, 0x80 ])) + // U+7Fzzyyxx (invalid) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xfd, 0xbf ])) + + // + // Sequences with five continuation bytes missing + // + + // Ill-formed 6-byte sequences. + // 1111110u 10uuuuuu 10zzzzzz 10zzyyyy 10yyyyxx 10xxxxxx + // U+uzzyyxx (invalid) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xfc ])) + // U+uuzzyyxx (invalid) + expectTrue(checkDecodeUTF8([], [ 0xfffd ], [ 0xfd ])) + + // + // Consecutive sequences with trailing bytes missing + // + + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, /**/ 0xfffd, 0xfffd, /**/ 0xfffd, 0xfffd, 0xfffd, + 0xfffd, 0xfffd, 0xfffd, 0xfffd, + 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, + 0xfffd, /**/ 0xfffd, /**/ 0xfffd, 0xfffd, 0xfffd, + 0xfffd, 0xfffd, 0xfffd, 0xfffd, + 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xc0, /**/ 0xe0, 0x80, /**/ 0xf0, 0x80, 0x80, + 0xf8, 0x80, 0x80, 0x80, + 0xfc, 0x80, 0x80, 0x80, 0x80, + 0xdf, /**/ 0xef, 0xbf, /**/ 0xf7, 0xbf, 0xbf, + 0xfb, 0xbf, 0xbf, 0xbf, + 0xfd, 0xbf, 0xbf, 0xbf, 0xbf ])) +} + +UTF8Decoder.test("OverlongSequences") { + // + // Overlong UTF-8 sequences + // + + // U+002F SOLIDUS + expectTrue(checkDecodeUTF8([ 0x002f ], [], [ 0x2f ])) + + // Overlong sequences of the above. + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xc0, 0xaf ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xe0, 0x80, 0xaf ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xf0, 0x80, 0x80, 0xaf ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xf8, 0x80, 0x80, 0x80, 0xaf ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xfc, 0x80, 0x80, 0x80, 0x80, 0xaf ])) + + // U+0000 NULL + expectTrue(checkDecodeUTF8([ 0x0000 ], [], [ 0x00 ])) + + // Overlong sequences of the above. + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xc0, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xe0, 0x80, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xf0, 0x80, 0x80, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xf8, 0x80, 0x80, 0x80, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xfc, 0x80, 0x80, 0x80, 0x80, 0x80 ])) + + // Other overlong and ill-formed sequences. + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xc0, 0xbf ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xc1, 0x80 ])) + expectTrue(checkDecodeUTF8([], [ 0xfffd, 0xfffd ], [ 0xc1, 0xbf ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xe0, 0x9f, 0xbf ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xed, 0xa0, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xed, 0xbf, 0xbf ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xf0, 0x8f, 0x80, 0x80 ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xf0, 0x8f, 0xbf, 0xbf ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xf8, 0x87, 0xbf, 0xbf, 0xbf ])) + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xfc, 0x83, 0xbf, 0xbf, 0xbf, 0xbf ])) +} + +UTF8Decoder.test("IsolatedSurrogates") { + // Unicode 6.3.0: + // + // D71. High-surrogate code point: A Unicode code point in the range + // U+D800 to U+DBFF. + // + // D73. Low-surrogate code point: A Unicode code point in the range + // U+DC00 to U+DFFF. + + // Note: U+E0100 is in UTF-16. + + // High-surrogates + + // U+D800 + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xed, 0xa0, 0x80 ])) + expectTrue(checkDecodeUTF8( + [ 0x0041 ], + [ 0xfffd, 0xfffd, 0xfffd, 0x0041 ], + [ 0x41, 0xed, 0xa0, 0x80, 0x41 ])) + + // U+DB40 + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xed, 0xac, 0xa0 ])) + + // U+DBFF + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xed, 0xaf, 0xbf ])) + + // Low-surrogates + + // U+DC00 + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xed, 0xb0, 0x80 ])) + + // U+DD00 + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xed, 0xb4, 0x80 ])) + + // U+DFFF + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd ], + [ 0xed, 0xbf, 0xbf ])) +} + +UTF8Decoder.test("SurrogatePairs") { + // Surrogate pairs + + // U+D800 U+DC00 + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xed, 0xa0, 0x80, 0xed, 0xb0, 0x80 ])) + + // U+D800 U+DD00 + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xed, 0xa0, 0x80, 0xed, 0xb4, 0x80 ])) + + // U+D800 U+DFFF + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xed, 0xa0, 0x80, 0xed, 0xbf, 0xbf ])) + + // U+DB40 U+DC00 + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xed, 0xac, 0xa0, 0xed, 0xb0, 0x80 ])) + + // U+DB40 U+DD00 + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xed, 0xac, 0xa0, 0xed, 0xb4, 0x80 ])) + + // U+DB40 U+DFFF + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xed, 0xac, 0xa0, 0xed, 0xbf, 0xbf ])) + + // U+DBFF U+DC00 + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xed, 0xaf, 0xbf, 0xed, 0xb0, 0x80 ])) + + // U+DBFF U+DD00 + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xed, 0xaf, 0xbf, 0xed, 0xb4, 0x80 ])) + + // U+DBFF U+DFFF + expectTrue(checkDecodeUTF8( + [], + [ 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd ], + [ 0xed, 0xaf, 0xbf, 0xed, 0xbf, 0xbf ])) +} + +UTF8Decoder.test("Noncharacters") { + // + // Noncharacters + // + + // Unicode 6.3.0: + // + // D14. Noncharacter: A code point that is permanently reserved for + // internal use and that should never be interchanged. Noncharacters + // consist of the values U+nFFFE and U+nFFFF (where n is from 0 to 1016) + // and the values U+FDD0..U+FDEF. + + // U+FFFE + expectTrue(checkDecodeUTF8([ 0xfffe ], [], [ 0xef, 0xbf, 0xbe ])) + + // U+FFFF + expectTrue(checkDecodeUTF8([ 0xffff ], [], [ 0xef, 0xbf, 0xbf ])) + + // U+1FFFE + expectTrue(checkDecodeUTF8([ 0x1fffe ], [], [ 0xf0, 0x9f, 0xbf, 0xbe ])) + + // U+1FFFF + expectTrue(checkDecodeUTF8([ 0x1ffff ], [], [ 0xf0, 0x9f, 0xbf, 0xbf ])) + + // U+2FFFE + expectTrue(checkDecodeUTF8([ 0x2fffe ], [], [ 0xf0, 0xaf, 0xbf, 0xbe ])) + + // U+2FFFF + expectTrue(checkDecodeUTF8([ 0x2ffff ], [], [ 0xf0, 0xaf, 0xbf, 0xbf ])) + + // U+3FFFE + expectTrue(checkDecodeUTF8([ 0x3fffe ], [], [ 0xf0, 0xbf, 0xbf, 0xbe ])) + + // U+3FFFF + expectTrue(checkDecodeUTF8([ 0x3ffff ], [], [ 0xf0, 0xbf, 0xbf, 0xbf ])) + + // U+4FFFE + expectTrue(checkDecodeUTF8([ 0x4fffe ], [], [ 0xf1, 0x8f, 0xbf, 0xbe ])) + + // U+4FFFF + expectTrue(checkDecodeUTF8([ 0x4ffff ], [], [ 0xf1, 0x8f, 0xbf, 0xbf ])) + + // U+5FFFE + expectTrue(checkDecodeUTF8([ 0x5fffe ], [], [ 0xf1, 0x9f, 0xbf, 0xbe ])) + + // U+5FFFF + expectTrue(checkDecodeUTF8([ 0x5ffff ], [], [ 0xf1, 0x9f, 0xbf, 0xbf ])) + + // U+6FFFE + expectTrue(checkDecodeUTF8([ 0x6fffe ], [], [ 0xf1, 0xaf, 0xbf, 0xbe ])) + + // U+6FFFF + expectTrue(checkDecodeUTF8([ 0x6ffff ], [], [ 0xf1, 0xaf, 0xbf, 0xbf ])) + + // U+7FFFE + expectTrue(checkDecodeUTF8([ 0x7fffe ], [], [ 0xf1, 0xbf, 0xbf, 0xbe ])) + + // U+7FFFF + expectTrue(checkDecodeUTF8([ 0x7ffff ], [], [ 0xf1, 0xbf, 0xbf, 0xbf ])) + + // U+8FFFE + expectTrue(checkDecodeUTF8([ 0x8fffe ], [], [ 0xf2, 0x8f, 0xbf, 0xbe ])) + + // U+8FFFF + expectTrue(checkDecodeUTF8([ 0x8ffff ], [], [ 0xf2, 0x8f, 0xbf, 0xbf ])) + + // U+9FFFE + expectTrue(checkDecodeUTF8([ 0x9fffe ], [], [ 0xf2, 0x9f, 0xbf, 0xbe ])) + + // U+9FFFF + expectTrue(checkDecodeUTF8([ 0x9ffff ], [], [ 0xf2, 0x9f, 0xbf, 0xbf ])) + + // U+AFFFE + expectTrue(checkDecodeUTF8([ 0xafffe ], [], [ 0xf2, 0xaf, 0xbf, 0xbe ])) + + // U+AFFFF + expectTrue(checkDecodeUTF8([ 0xaffff ], [], [ 0xf2, 0xaf, 0xbf, 0xbf ])) + + // U+BFFFE + expectTrue(checkDecodeUTF8([ 0xbfffe ], [], [ 0xf2, 0xbf, 0xbf, 0xbe ])) + + // U+BFFFF + expectTrue(checkDecodeUTF8([ 0xbffff ], [], [ 0xf2, 0xbf, 0xbf, 0xbf ])) + + // U+CFFFE + expectTrue(checkDecodeUTF8([ 0xcfffe ], [], [ 0xf3, 0x8f, 0xbf, 0xbe ])) + + // U+CFFFF + expectTrue(checkDecodeUTF8([ 0xcfffF ], [], [ 0xf3, 0x8f, 0xbf, 0xbf ])) + + // U+DFFFE + expectTrue(checkDecodeUTF8([ 0xdfffe ], [], [ 0xf3, 0x9f, 0xbf, 0xbe ])) + + // U+DFFFF + expectTrue(checkDecodeUTF8([ 0xdffff ], [], [ 0xf3, 0x9f, 0xbf, 0xbf ])) + + // U+EFFFE + expectTrue(checkDecodeUTF8([ 0xefffe ], [], [ 0xf3, 0xaf, 0xbf, 0xbe ])) + + // U+EFFFF + expectTrue(checkDecodeUTF8([ 0xeffff ], [], [ 0xf3, 0xaf, 0xbf, 0xbf ])) + + // U+FFFFE + expectTrue(checkDecodeUTF8([ 0xffffe ], [], [ 0xf3, 0xbf, 0xbf, 0xbe ])) + + // U+FFFFF + expectTrue(checkDecodeUTF8([ 0xfffff ], [], [ 0xf3, 0xbf, 0xbf, 0xbf ])) + + // U+10FFFE + expectTrue(checkDecodeUTF8([ 0x10fffe ], [], [ 0xf4, 0x8f, 0xbf, 0xbe ])) + + // U+10FFFF + expectTrue(checkDecodeUTF8([ 0x10ffff ], [], [ 0xf4, 0x8f, 0xbf, 0xbf ])) + + // U+FDD0 + expectTrue(checkDecodeUTF8([ 0xfdd0 ], [], [ 0xef, 0xb7, 0x90 ])) + + // U+FDD1 + expectTrue(checkDecodeUTF8([ 0xfdd1 ], [], [ 0xef, 0xb7, 0x91 ])) + + // U+FDD2 + expectTrue(checkDecodeUTF8([ 0xfdd2 ], [], [ 0xef, 0xb7, 0x92 ])) + + // U+FDD3 + expectTrue(checkDecodeUTF8([ 0xfdd3 ], [], [ 0xef, 0xb7, 0x93 ])) + + // U+FDD4 + expectTrue(checkDecodeUTF8([ 0xfdd4 ], [], [ 0xef, 0xb7, 0x94 ])) + + // U+FDD5 + expectTrue(checkDecodeUTF8([ 0xfdd5 ], [], [ 0xef, 0xb7, 0x95 ])) + + // U+FDD6 + expectTrue(checkDecodeUTF8([ 0xfdd6 ], [], [ 0xef, 0xb7, 0x96 ])) + + // U+FDD7 + expectTrue(checkDecodeUTF8([ 0xfdd7 ], [], [ 0xef, 0xb7, 0x97 ])) + + // U+FDD8 + expectTrue(checkDecodeUTF8([ 0xfdd8 ], [], [ 0xef, 0xb7, 0x98 ])) + + // U+FDD9 + expectTrue(checkDecodeUTF8([ 0xfdd9 ], [], [ 0xef, 0xb7, 0x99 ])) + + // U+FDDA + expectTrue(checkDecodeUTF8([ 0xfdda ], [], [ 0xef, 0xb7, 0x9a ])) + + // U+FDDB + expectTrue(checkDecodeUTF8([ 0xfddb ], [], [ 0xef, 0xb7, 0x9b ])) + + // U+FDDC + expectTrue(checkDecodeUTF8([ 0xfddc ], [], [ 0xef, 0xb7, 0x9c ])) + + // U+FDDD + expectTrue(checkDecodeUTF8([ 0xfddd ], [], [ 0xef, 0xb7, 0x9d ])) + + // U+FDDE + expectTrue(checkDecodeUTF8([ 0xfdde ], [], [ 0xef, 0xb7, 0x9e ])) + + // U+FDDF + expectTrue(checkDecodeUTF8([ 0xfddf ], [], [ 0xef, 0xb7, 0x9f ])) + + // U+FDE0 + expectTrue(checkDecodeUTF8([ 0xfde0 ], [], [ 0xef, 0xb7, 0xa0 ])) + + // U+FDE1 + expectTrue(checkDecodeUTF8([ 0xfde1 ], [], [ 0xef, 0xb7, 0xa1 ])) + + // U+FDE2 + expectTrue(checkDecodeUTF8([ 0xfde2 ], [], [ 0xef, 0xb7, 0xa2 ])) + + // U+FDE3 + expectTrue(checkDecodeUTF8([ 0xfde3 ], [], [ 0xef, 0xb7, 0xa3 ])) + + // U+FDE4 + expectTrue(checkDecodeUTF8([ 0xfde4 ], [], [ 0xef, 0xb7, 0xa4 ])) + + // U+FDE5 + expectTrue(checkDecodeUTF8([ 0xfde5 ], [], [ 0xef, 0xb7, 0xa5 ])) + + // U+FDE6 + expectTrue(checkDecodeUTF8([ 0xfde6 ], [], [ 0xef, 0xb7, 0xa6 ])) + + // U+FDE7 + expectTrue(checkDecodeUTF8([ 0xfde7 ], [], [ 0xef, 0xb7, 0xa7 ])) + + // U+FDE8 + expectTrue(checkDecodeUTF8([ 0xfde8 ], [], [ 0xef, 0xb7, 0xa8 ])) + + // U+FDE9 + expectTrue(checkDecodeUTF8([ 0xfde9 ], [], [ 0xef, 0xb7, 0xa9 ])) + + // U+FDEA + expectTrue(checkDecodeUTF8([ 0xfdea ], [], [ 0xef, 0xb7, 0xaa ])) + + // U+FDEB + expectTrue(checkDecodeUTF8([ 0xfdeb ], [], [ 0xef, 0xb7, 0xab ])) + + // U+FDEC + expectTrue(checkDecodeUTF8([ 0xfdec ], [], [ 0xef, 0xb7, 0xac ])) + + // U+FDED + expectTrue(checkDecodeUTF8([ 0xfded ], [], [ 0xef, 0xb7, 0xad ])) + + // U+FDEE + expectTrue(checkDecodeUTF8([ 0xfdee ], [], [ 0xef, 0xb7, 0xae ])) + + // U+FDEF + expectTrue(checkDecodeUTF8([ 0xfdef ], [], [ 0xef, 0xb7, 0xaf ])) + + // U+FDF0 + expectTrue(checkDecodeUTF8([ 0xfdf0 ], [], [ 0xef, 0xb7, 0xb0 ])) + + // U+FDF1 + expectTrue(checkDecodeUTF8([ 0xfdf1 ], [], [ 0xef, 0xb7, 0xb1 ])) + + // U+FDF2 + expectTrue(checkDecodeUTF8([ 0xfdf2 ], [], [ 0xef, 0xb7, 0xb2 ])) + + // U+FDF3 + expectTrue(checkDecodeUTF8([ 0xfdf3 ], [], [ 0xef, 0xb7, 0xb3 ])) + + // U+FDF4 + expectTrue(checkDecodeUTF8([ 0xfdf4 ], [], [ 0xef, 0xb7, 0xb4 ])) + + // U+FDF5 + expectTrue(checkDecodeUTF8([ 0xfdf5 ], [], [ 0xef, 0xb7, 0xb5 ])) + + // U+FDF6 + expectTrue(checkDecodeUTF8([ 0xfdf6 ], [], [ 0xef, 0xb7, 0xb6 ])) + + // U+FDF7 + expectTrue(checkDecodeUTF8([ 0xfdf7 ], [], [ 0xef, 0xb7, 0xb7 ])) + + // U+FDF8 + expectTrue(checkDecodeUTF8([ 0xfdf8 ], [], [ 0xef, 0xb7, 0xb8 ])) + + // U+FDF9 + expectTrue(checkDecodeUTF8([ 0xfdf9 ], [], [ 0xef, 0xb7, 0xb9 ])) + + // U+FDFA + expectTrue(checkDecodeUTF8([ 0xfdfa ], [], [ 0xef, 0xb7, 0xba ])) + + // U+FDFB + expectTrue(checkDecodeUTF8([ 0xfdfb ], [], [ 0xef, 0xb7, 0xbb ])) + + // U+FDFC + expectTrue(checkDecodeUTF8([ 0xfdfc ], [], [ 0xef, 0xb7, 0xbc ])) + + // U+FDFD + expectTrue(checkDecodeUTF8([ 0xfdfd ], [], [ 0xef, 0xb7, 0xbd ])) + + // U+FDFE + expectTrue(checkDecodeUTF8([ 0xfdfe ], [], [ 0xef, 0xb7, 0xbe ])) + + // U+FDFF + expectTrue(checkDecodeUTF8([ 0xfdff ], [], [ 0xef, 0xb7, 0xbf ])) +} + +var UTF16Decoder = TestSuite("UTF16Decoder") + +UTF16Decoder.test("UTF16.transcodedLength") { + do { + let u8: [UTF8.CodeUnit] = [ 0, 1, 2, 3, 4, 5 ] + let (count, isASCII) = UTF16.transcodedLength( + of: u8.makeIterator(), + decodedAs: UTF8.self, + repairingIllFormedSequences: false)! + expectEqual(6, count) + expectTrue(isASCII) + } + + do { + // "€" == U+20AC. + let u8: [UTF8.CodeUnit] = [ 0xF0, 0xA4, 0xAD, 0xA2 ] + let (count, isASCII) = UTF16.transcodedLength( + of: u8.makeIterator(), + decodedAs: UTF8.self, + repairingIllFormedSequences: false)! + expectEqual(2, count) + expectFalse(isASCII) + } + + do { + let u16: [UTF16.CodeUnit] = [ 6, 7, 8, 9, 10, 11 ] + let (count, isASCII) = UTF16.transcodedLength( + of: u16.makeIterator(), + decodedAs: UTF16.self, + repairingIllFormedSequences: false)! + expectEqual(6, count) + expectTrue(isASCII) + } +} + +UTF16Decoder.test("Decoding1").forEach(in: utfTests) { + test in + + expectTrue( + checkDecodeUTF16( + test.utf32, test.utf32RepairedTail, test.utf16), + stackTrace: test.loc.withCurrentLoc()) + return () +} + +UTF16Decoder.test("Decoding2") { + for (name, batch) in utf16Tests { + print("Batch: \(name)") + for test in batch { + expectTrue(checkDecodeUTF16(test.scalarsHead, test.scalarsRepairedTail, + test.encoded), stackTrace: test.loc.withCurrentLoc()) + } + } +} + +public struct UTF16Test { + public let scalarsHead: [UInt32] + public let scalarsRepairedTail: [UInt32] + public let encoded: [UInt16] + public let loc: SourceLoc + + public init( + _ scalarsHead: [UInt32], _ scalarsRepairedTail: [UInt32], + _ encoded: [UInt16], + file: String = #file, line: UInt = #line + ) { + self.scalarsHead = scalarsHead + self.scalarsRepairedTail = scalarsRepairedTail + self.encoded = encoded + self.loc = SourceLoc(file, line, comment: "test data") + } +} + +public let utf16Tests = [ + "Incomplete": [ + // + // Incomplete sequences that end right before EOF. + // + + // U+D800 (high-surrogate) + UTF16Test([], [ 0xFFFD ], [ 0xD800 ]), + + // U+D800 (high-surrogate) + // U+D800 (high-surrogate) + UTF16Test([], [ 0xFFFD, 0xFFFD ], [ 0xD800, 0xD800 ]), + + // U+0041 LATIN CAPITAL LETTER A + // U+D800 (high-surrogate) + UTF16Test([ 0x0041 ], [ 0xFFFD ], [ 0x0041, 0xD800 ]), + + // U+10000 LINEAR B SYLLABLE B008 A + // U+D800 (high-surrogate) + UTF16Test( + [ 0x0001_0000 ], [ 0xFFFD ], + [ 0xD800, 0xDC00, 0xD800 ]), + + // + // Incomplete sequences with more code units following them. + // + + // U+D800 (high-surrogate) + // U+0041 LATIN CAPITAL LETTER A + UTF16Test([], [ 0xFFFD, 0x0041 ], [ 0xD800, 0x0041 ]), + + // U+D800 (high-surrogate) + // U+10000 LINEAR B SYLLABLE B008 A + UTF16Test( + [], [ 0xFFFD, 0x0001_0000 ], + [ 0xD800, 0xD800, 0xDC00 ]), + + // U+0041 LATIN CAPITAL LETTER A + // U+D800 (high-surrogate) + // U+0041 LATIN CAPITAL LETTER A + UTF16Test( + [ 0x0041 ], [ 0xFFFD, 0x0041 ], + [ 0x0041, 0xD800, 0x0041 ]), + + // U+0041 LATIN CAPITAL LETTER A + // U+D800 (high-surrogate) + // U+10000 LINEAR B SYLLABLE B008 A + UTF16Test( + [ 0x0041 ], [ 0xFFFD, 0x0001_0000 ], + [ 0x0041, 0xD800, 0xD800, 0xDC00 ]), + + // U+0041 LATIN CAPITAL LETTER A + // U+D800 (high-surrogate) + // U+DB40 (high-surrogate) + // U+0041 LATIN CAPITAL LETTER A + UTF16Test( + [ 0x0041 ], [ 0xFFFD, 0xFFFD, 0x0041 ], + [ 0x0041, 0xD800, 0xDB40, 0x0041 ]), + + // U+0041 LATIN CAPITAL LETTER A + // U+D800 (high-surrogate) + // U+DB40 (high-surrogate) + // U+10000 LINEAR B SYLLABLE B008 A + UTF16Test( + [ 0x0041 ], [ 0xFFFD, 0xFFFD, 0x0001_0000 ], + [ 0x0041, 0xD800, 0xDB40, 0xD800, 0xDC00 ]), + + // U+0041 LATIN CAPITAL LETTER A + // U+D800 (high-surrogate) + // U+DB40 (high-surrogate) + // U+DBFF (high-surrogate) + // U+0041 LATIN CAPITAL LETTER A + UTF16Test( + [ 0x0041 ], [ 0xFFFD, 0xFFFD, 0xFFFD, 0x0041 ], + [ 0x0041, 0xD800, 0xDB40, 0xDBFF, 0x0041 ]), + + // U+0041 LATIN CAPITAL LETTER A + // U+D800 (high-surrogate) + // U+DB40 (high-surrogate) + // U+DBFF (high-surrogate) + // U+10000 LINEAR B SYLLABLE B008 A + UTF16Test( + [ 0x0041 ], [ 0xFFFD, 0xFFFD, 0xFFFD, 0x0001_0000 ], + [ 0x0041, 0xD800, 0xDB40, 0xDBFF, 0xD800, 0xDC00 ]), + ], + + "IllFormed": [ + // + // Low-surrogate right before EOF. + // + + // U+DC00 (low-surrogate) + UTF16Test([], [ 0xFFFD ], [ 0xDC00 ]), + + // U+DC00 (low-surrogate) + // U+DC00 (low-surrogate) + UTF16Test([], [ 0xFFFD, 0xFFFD ], [ 0xDC00, 0xDC00 ]), + + // U+0041 LATIN CAPITAL LETTER A + // U+DC00 (low-surrogate) + UTF16Test([ 0x0041 ], [ 0xFFFD ], [ 0x0041, 0xDC00 ]), + + // U+10000 LINEAR B SYLLABLE B008 A + // U+DC00 (low-surrogate) + UTF16Test( + [ 0x0001_0000 ], [ 0xFFFD ], + [ 0xD800, 0xDC00, 0xDC00 ]), + + // + // Low-surrogate with more code units following it. + // + + // U+DC00 (low-surrogate) + // U+0041 LATIN CAPITAL LETTER A + UTF16Test([], [ 0xFFFD, 0x0041 ], [ 0xDC00, 0x0041 ]), + + // U+DC00 (low-surrogate) + // U+10000 LINEAR B SYLLABLE B008 A + UTF16Test( + [], [ 0xFFFD, 0x0001_0000 ], + [ 0xDC00, 0xD800, 0xDC00 ]), + + // U+0041 LATIN CAPITAL LETTER A + // U+DC00 (low-surrogate) + // U+0041 LATIN CAPITAL LETTER A + UTF16Test( + [ 0x0041 ], [ 0xFFFD, 0x0041 ], + [ 0x0041, 0xDC00, 0x0041 ]), + + // U+0041 LATIN CAPITAL LETTER A + // U+DC00 (low-surrogate) + // U+10000 LINEAR B SYLLABLE B008 A + UTF16Test( + [ 0x0041 ], [ 0xFFFD, 0x0001_0000 ], + [ 0x0041, 0xDC00, 0xD800, 0xDC00 ]), + + // U+0041 LATIN CAPITAL LETTER A + // U+DC00 (low-surrogate) + // U+DD00 (low-surrogate) + // U+0041 LATIN CAPITAL LETTER A + UTF16Test( + [ 0x0041 ], [ 0xFFFD, 0xFFFD, 0x0041 ], + [ 0x0041, 0xDC00, 0xDD00, 0x0041 ]), + + // U+0041 LATIN CAPITAL LETTER A + // U+DC00 (low-surrogate) + // U+DD00 (low-surrogate) + // U+10000 LINEAR B SYLLABLE B008 A + UTF16Test( + [ 0x0041 ], [ 0xFFFD, 0xFFFD, 0x0001_0000 ], + [ 0x0041, 0xDC00, 0xDD00, 0xD800, 0xDC00 ]), + + // U+0041 LATIN CAPITAL LETTER A + // U+DC00 (low-surrogate) + // U+DD00 (low-surrogate) + // U+DFFF (low-surrogate) + // U+0041 LATIN CAPITAL LETTER A + UTF16Test( + [ 0x0041 ], [ 0xFFFD, 0xFFFD, 0xFFFD, 0x0041 ], + [ 0x0041, 0xDC00, 0xDD00, 0xDFFF, 0x0041 ]), + + // U+0041 LATIN CAPITAL LETTER A + // U+DC00 (low-surrogate) + // U+DD00 (low-surrogate) + // U+DFFF (low-surrogate) + // U+10000 LINEAR B SYLLABLE B008 A + UTF16Test( + [ 0x0041 ], [ 0xFFFD, 0xFFFD, 0xFFFD, 0x0001_0000 ], + [ 0x0041, 0xDC00, 0xDD00, 0xDFFF, 0xD800, 0xDC00 ]), + + // + // Low-surrogate followed by high-surrogate. + // + + // U+DC00 (low-surrogate) + // U+D800 (high-surrogate) + UTF16Test([], [ 0xFFFD, 0xFFFD ], [ 0xDC00, 0xD800 ]), + + // U+DC00 (low-surrogate) + // U+DB40 (high-surrogate) + UTF16Test([], [ 0xFFFD, 0xFFFD ], [ 0xDC00, 0xDB40 ]), + + // U+DC00 (low-surrogate) + // U+DBFF (high-surrogate) + UTF16Test([], [ 0xFFFD, 0xFFFD ], [ 0xDC00, 0xDBFF ]), + + + // U+DD00 (low-surrogate) + // U+D800 (high-surrogate) + UTF16Test([], [ 0xFFFD, 0xFFFD ], [ 0xDD00, 0xD800 ]), + + // U+DD00 (low-surrogate) + // U+DB40 (high-surrogate) + UTF16Test([], [ 0xFFFD, 0xFFFD ], [ 0xDD00, 0xDB40 ]), + + // U+DD00 (low-surrogate) + // U+DBFF (high-surrogate) + UTF16Test([], [ 0xFFFD, 0xFFFD ], [ 0xDD00, 0xDBFF ]), + + + // U+DFFF (low-surrogate) + // U+D800 (high-surrogate) + UTF16Test([], [ 0xFFFD, 0xFFFD ], [ 0xDFFF, 0xD800 ]), + + // U+DFFF (low-surrogate) + // U+DB40 (high-surrogate) + UTF16Test([], [ 0xFFFD, 0xFFFD ], [ 0xDFFF, 0xDB40 ]), + + // U+DFFF (low-surrogate) + // U+DBFF (high-surrogate) + UTF16Test([], [ 0xFFFD, 0xFFFD ], [ 0xDFFF, 0xDBFF ]), + + + // U+DC00 (low-surrogate) + // U+D800 (high-surrogate) + // U+0041 LATIN CAPITAL LETTER A + UTF16Test( + [], [ 0xFFFD, 0xFFFD, 0x0041 ], + [ 0xDC00, 0xD800, 0x0041 ]), + + // U+DC00 (low-surrogate) + // U+D800 (high-surrogate) + // U+10000 LINEAR B SYLLABLE B008 A + UTF16Test( + [], [ 0xFFFD, 0xFFFD, 0x10000 ], + [ 0xDC00, 0xD800, 0xD800, 0xDC00 ]), + ], +] + +runAllTests() + +#else +//===--- benchmarking -----------------------------------------------------===// + +@inline(never) +public func run_UTF8Decode(_ N: Int) { + // 1-byte sequences + // This test case is the longest as it's the most performance sensitive. + let ascii = "Swift is a multi-paradigm, compiled programming language created for iOS, OS X, watchOS, tvOS and Linux development by Apple Inc. Swift is designed to work with Apple's Cocoa and Cocoa Touch frameworks and the large body of existing Objective-C code written for Apple products. Swift is intended to be more resilient to erroneous code (\"safer\") than Objective-C and also more concise. It is built with the LLVM compiler framework included in Xcode 6 and later and uses the Objective-C runtime, which allows C, Objective-C, C++ and Swift code to run within a single program." + // 2-byte sequences + let russian = "Ру́сский язы́к один из восточнославянских языков, национальный язык русского народа." + // 3-byte sequences + let japanese = "日本語(にほんご、にっぽんご)は、主に日本国内や日本人同士の間で使われている言語である。" + // 4-byte sequences + // Most commonly emoji, which are usually mixed with other text. + let emoji = "Panda 🐼, Dog 🐶, Cat 🐱, Mouse 🐭." + + let strings = [ascii, russian, japanese, emoji].map { Array($0.utf8) } + + func isEmpty(_ result: UnicodeDecodingResult) -> Bool { + switch result { + case .emptyInput: + return true + default: + return false + } + } + + var total: UInt32 = 0 + + for _ in 1...200*N { + for string in strings { +#if BASELINE + _ = transcode( + string.makeIterator(), from: UTF8.self, to: UTF32.self, + stoppingOnError: false + ) { + total = total &+ $0 + } +#else + #if FORWARD + var it = string.makeIterator() + typealias D = UTF8.ForwardDecoder + D.decode(&it, repairingIllFormedSequences: true) { total = total &+ $0.value } + #elseif REVERSE + var it = string.reversed().makeIterator() + typealias D = UTF8.ReverseDecoder + D.decode(&it, repairingIllFormedSequences: true) { total = total &+ $0.value } + #elseif SEQUENCE + for s in Unicode.DefaultScalarView(string, fromEncoding: UTF8.self) { + total = total &+ s.value + } + #elseif COLLECTION + let scalars = Unicode.DefaultScalarView(string, fromEncoding: UTF8.self) + var i = scalars.startIndex + while i != scalars.endIndex { + total = total &+ scalars[i].value + i = scalars.index(after: i) + } +#elseif REVERSE_COLLECTION + let scalars = Unicode.DefaultScalarView(string, fromEncoding: UTF8.self) + var i = scalars.endIndex + while i != scalars.startIndex { + i = scalars.index(before: i) + total = total &+ scalars[i].value + } + #else + Error_Unknown_Benchmark() + #endif +#endif + } + } + if CommandLine.arguments.count > 1000 { print(total) } +} + +run_UTF8Decode(10000) +#endif + diff --git a/validation-test/compiler_crashers_2_fixed/0042-rdar21775089.swift b/validation-test/compiler_crashers_2_fixed/0042-rdar21775089.swift index 065d92159e7..790285361c1 100644 --- a/validation-test/compiler_crashers_2_fixed/0042-rdar21775089.swift +++ b/validation-test/compiler_crashers_2_fixed/0042-rdar21775089.swift @@ -7,7 +7,7 @@ protocol MySequenceType {} protocol MyIndexableType {} protocol MyCollectionType : MySequenceType, MyIndexableType { - typealias SubSequence = MySlice + associatedtype SubSequence = MySlice func makeSubSequence() -> SubSequence } extension MyCollectionType { @@ -18,7 +18,7 @@ extension MyCollectionType { } protocol MyMutableCollectionType : MyCollectionType { - typealias SubSequence = MyMutableSlice + associatedtype SubSequence = MyMutableSlice } extension MyMutableCollectionType { func makeSubSequence() -> MyMutableSlice { diff --git a/validation-test/compiler_crashers_2/0097-rdar32077627.swift b/validation-test/compiler_crashers_2_fixed/0097-rdar32077627.swift similarity index 55% rename from validation-test/compiler_crashers_2/0097-rdar32077627.swift rename to validation-test/compiler_crashers_2_fixed/0097-rdar32077627.swift index e55af139e2b..431b3001664 100644 --- a/validation-test/compiler_crashers_2/0097-rdar32077627.swift +++ b/validation-test/compiler_crashers_2_fixed/0097-rdar32077627.swift @@ -1,3 +1,3 @@ -// RUN: not --crash %target-swift-frontend -typecheck -primary-file %s +// RUN: not %target-swift-frontend -typecheck -primary-file %s func hexEncodeBytes(_ bytes: T) where T.Generator.Element == UInt8 { } diff --git a/validation-test/compiler_crashers_2/0100-sr4295.swift b/validation-test/compiler_crashers_2_fixed/0100-sr4295.swift similarity index 87% rename from validation-test/compiler_crashers_2/0100-sr4295.swift rename to validation-test/compiler_crashers_2_fixed/0100-sr4295.swift index c3952ee27b1..699a1ccea49 100644 --- a/validation-test/compiler_crashers_2/0100-sr4295.swift +++ b/validation-test/compiler_crashers_2_fixed/0100-sr4295.swift @@ -1,4 +1,4 @@ -// RUN: not --crash %target-swift-frontend -emit-ir -primary-file %s +// RUN: not %target-swift-frontend -emit-ir -primary-file %s // REQUIRES: asserts diff --git a/validation-test/compiler_crashers_2/0101-sr5014.swift b/validation-test/compiler_crashers_2_fixed/0101-sr5014.swift similarity index 61% rename from validation-test/compiler_crashers_2/0101-sr5014.swift rename to validation-test/compiler_crashers_2_fixed/0101-sr5014.swift index cf6b121ed53..ced11e6174d 100644 --- a/validation-test/compiler_crashers_2/0101-sr5014.swift +++ b/validation-test/compiler_crashers_2_fixed/0101-sr5014.swift @@ -1,6 +1,4 @@ -// RUN: not --crash %target-swift-frontend -emit-ir -primary-file %s - -// REQUIRES: asserts +// RUN: not %target-swift-frontend -emit-ir -primary-file %s struct Version { } diff --git a/validation-test/compiler_crashers_2_fixed/0107-rdar32700180.swift b/validation-test/compiler_crashers_2_fixed/0107-rdar32700180.swift new file mode 100644 index 00000000000..97b296af8d1 --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/0107-rdar32700180.swift @@ -0,0 +1,14 @@ +// RUN: %target-swift-frontend %s -emit-ir +struct X { + func f(_: T.Z) { } +} + +protocol P { + associatedtype A + associatedtype B +} + +protocol Q { + associatedtype C: P + typealias Z = (C.A, C.B) +} diff --git a/validation-test/compiler_crashers_2_fixed/0108-sr4088.swift b/validation-test/compiler_crashers_2_fixed/0108-sr4088.swift new file mode 100644 index 00000000000..83f9514de70 --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/0108-sr4088.swift @@ -0,0 +1,23 @@ +// RUN: %target-swift-frontend -emit-ir -primary-file %s + +class UITableViewCell {} +class UITableView {} + +extension UITableViewCell: ReusableViewProtocol { + public typealias ParentView = UITableView +} + +protocol ReusableViewProtocol { + associatedtype ParentView +} + +protocol ReusableViewFactoryProtocol { + associatedtype View: ReusableViewProtocol + func configure(parentView: View.ParentView) +} + +extension ReusableViewFactoryProtocol where View: UITableViewCell { + func tableCellFor(tableView: UITableView) { + configure(parentView: tableView) + } +} diff --git a/validation-test/compiler_crashers_2_fixed/0110-sr4786.swift b/validation-test/compiler_crashers_2_fixed/0110-sr4786.swift new file mode 100644 index 00000000000..7712938bfb2 --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/0110-sr4786.swift @@ -0,0 +1,13 @@ +// RUN: not %target-swift-frontend %s -typecheck + +public protocol _UTFEncoding { + associatedtype EncodedScalar where EncodedScalar == Int +} + +public protocol UnicodeEncoding { + associatedtype EncodedScalar: BidirectionalCollection +} + +public protocol _UTFParser { + associatedtype Encoding: UnicodeEncoding, _UTFEncoding +} diff --git a/validation-test/compiler_crashers/28706-conformance-failed-to-find-pas-conformance-to-known-protocol.swift b/validation-test/compiler_crashers_fixed/28706-conformance-failed-to-find-pas-conformance-to-known-protocol.swift similarity index 89% rename from validation-test/compiler_crashers/28706-conformance-failed-to-find-pas-conformance-to-known-protocol.swift rename to validation-test/compiler_crashers_fixed/28706-conformance-failed-to-find-pas-conformance-to-known-protocol.swift index 8df4f0e359b..8be1db13a9f 100644 --- a/validation-test/compiler_crashers/28706-conformance-failed-to-find-pas-conformance-to-known-protocol.swift +++ b/validation-test/compiler_crashers_fixed/28706-conformance-failed-to-find-pas-conformance-to-known-protocol.swift @@ -6,5 +6,5 @@ // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // REQUIRES: asserts -// RUN: not --crash %target-swift-frontend %s -emit-ir +// RUN: not %target-swift-frontend %s -emit-ir protocol P{let c{}typealias e:RangeReplaceableCollection}extension P{typealias e:a diff --git a/validation-test/compiler_crashers/28738-impl-genericparams-empty-key-depth-impl-genericparams-back-getdepth-key-index-im.swift b/validation-test/compiler_crashers_fixed/28738-impl-genericparams-empty-key-depth-impl-genericparams-back-getdepth-key-index-im.swift similarity index 88% rename from validation-test/compiler_crashers/28738-impl-genericparams-empty-key-depth-impl-genericparams-back-getdepth-key-index-im.swift rename to validation-test/compiler_crashers_fixed/28738-impl-genericparams-empty-key-depth-impl-genericparams-back-getdepth-key-index-im.swift index e8b8e2a19c5..f54117fe965 100644 --- a/validation-test/compiler_crashers/28738-impl-genericparams-empty-key-depth-impl-genericparams-back-getdepth-key-index-im.swift +++ b/validation-test/compiler_crashers_fixed/28738-impl-genericparams-empty-key-depth-impl-genericparams-back-getdepth-key-index-im.swift @@ -6,5 +6,5 @@ // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // REQUIRES: asserts -// RUN: not --crash %target-swift-frontend %s -emit-ir +// RUN: not %target-swift-frontend %s -emit-ir protocol P}extension P{{}typealias a:P}extension P.a{protocol P diff --git a/validation-test/compiler_crashers/28758-swift-genericsignaturebuilder-resolvesuperconformance-swift-genericsignaturebuil.swift b/validation-test/compiler_crashers_fixed/28758-swift-genericsignaturebuilder-resolvesuperconformance-swift-genericsignaturebuil.swift similarity index 88% rename from validation-test/compiler_crashers/28758-swift-genericsignaturebuilder-resolvesuperconformance-swift-genericsignaturebuil.swift rename to validation-test/compiler_crashers_fixed/28758-swift-genericsignaturebuilder-resolvesuperconformance-swift-genericsignaturebuil.swift index 456a3b45861..68538284eda 100644 --- a/validation-test/compiler_crashers/28758-swift-genericsignaturebuilder-resolvesuperconformance-swift-genericsignaturebuil.swift +++ b/validation-test/compiler_crashers_fixed/28758-swift-genericsignaturebuilder-resolvesuperconformance-swift-genericsignaturebuil.swift @@ -5,5 +5,5 @@ // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// RUN: not --crash %target-swift-frontend %s -emit-ir +// RUN: not %target-swift-frontend %s -emit-ir protocol P{{}typealias e:a{}}class a:P=extension P{typealias e:Self diff --git a/validation-test/compiler_crashers/28764-swift-protocolconformanceref-llvm-function-ref-swift-protocolconformanceref-swif.swift b/validation-test/compiler_crashers_fixed/28764-swift-protocolconformanceref-llvm-function-ref-swift-protocolconformanceref-swif.swift similarity index 88% rename from validation-test/compiler_crashers/28764-swift-protocolconformanceref-llvm-function-ref-swift-protocolconformanceref-swif.swift rename to validation-test/compiler_crashers_fixed/28764-swift-protocolconformanceref-llvm-function-ref-swift-protocolconformanceref-swif.swift index 639dc6bc4ef..f254454afec 100644 --- a/validation-test/compiler_crashers/28764-swift-protocolconformanceref-llvm-function-ref-swift-protocolconformanceref-swif.swift +++ b/validation-test/compiler_crashers_fixed/28764-swift-protocolconformanceref-llvm-function-ref-swift-protocolconformanceref-swif.swift @@ -5,5 +5,5 @@ // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// RUN: not --crash %target-swift-frontend %s -emit-ir +// RUN: not %target-swift-frontend %s -emit-ir protocol P{typealias a}{protocol A:P{{}class a{{}}typealias a:RangeReplaceableCollection diff --git a/validation-test/compiler_crashers/28770-selfty-isequal-proto-getselfinterfacetype.swift b/validation-test/compiler_crashers_fixed/28770-selfty-isequal-proto-getselfinterfacetype.swift similarity index 88% rename from validation-test/compiler_crashers/28770-selfty-isequal-proto-getselfinterfacetype.swift rename to validation-test/compiler_crashers_fixed/28770-selfty-isequal-proto-getselfinterfacetype.swift index 2cf59258fe8..8c2d8eaaace 100644 --- a/validation-test/compiler_crashers/28770-selfty-isequal-proto-getselfinterfacetype.swift +++ b/validation-test/compiler_crashers_fixed/28770-selfty-isequal-proto-getselfinterfacetype.swift @@ -6,5 +6,5 @@ // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // REQUIRES: asserts -// RUN: not --crash %target-swift-frontend %s -emit-ir +// RUN: not %target-swift-frontend %s -emit-ir protocol P{protocol b:P{{}typealias e:a.a}typealias a diff --git a/validation-test/compiler_crashers/28774-swift-genericenvironment-queryinterfacetypesubstitutions-operator-swift-substitu.swift b/validation-test/compiler_crashers_fixed/28774-swift-genericenvironment-queryinterfacetypesubstitutions-operator-swift-substitu.swift similarity index 88% rename from validation-test/compiler_crashers/28774-swift-genericenvironment-queryinterfacetypesubstitutions-operator-swift-substitu.swift rename to validation-test/compiler_crashers_fixed/28774-swift-genericenvironment-queryinterfacetypesubstitutions-operator-swift-substitu.swift index f40874779df..3a3afa4ade0 100644 --- a/validation-test/compiler_crashers/28774-swift-genericenvironment-queryinterfacetypesubstitutions-operator-swift-substitu.swift +++ b/validation-test/compiler_crashers_fixed/28774-swift-genericenvironment-queryinterfacetypesubstitutions-operator-swift-substitu.swift @@ -5,6 +5,6 @@ // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// RUN: not --crash %target-swift-frontend %s -emit-ir +// RUN: not %target-swift-frontend %s -emit-ir protocol P{typealias e:P.e protocol P{typealias e:Self diff --git a/validation-test/compiler_crashers_fixed/28775-gpdecl-getdepth-generictypeparamdecl-invaliddepth-parameter-hasnt-been-validated.swift b/validation-test/compiler_crashers_fixed/28775-gpdecl-getdepth-generictypeparamdecl-invaliddepth-parameter-hasnt-been-validated.swift new file mode 100644 index 00000000000..33a33753adb --- /dev/null +++ b/validation-test/compiler_crashers_fixed/28775-gpdecl-getdepth-generictypeparamdecl-invaliddepth-parameter-hasnt-been-validated.swift @@ -0,0 +1,10 @@ +// This source file is part of the Swift.org open source project +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + +// REQUIRES: asserts +// RUN: not %target-swift-frontend %s -emit-ir +protocol P{{}protocol A{typealias e{}}typealias a=A}extension P.a{protocol P diff --git a/validation-test/compiler_crashers_fixed/28788-conformance-isconcrete-concrete-isexistentialtype.swift b/validation-test/compiler_crashers_fixed/28788-conformance-isconcrete-concrete-isexistentialtype.swift new file mode 100644 index 00000000000..f0e4bf627a3 --- /dev/null +++ b/validation-test/compiler_crashers_fixed/28788-conformance-isconcrete-concrete-isexistentialtype.swift @@ -0,0 +1,13 @@ +// This source file is part of the Swift.org open source project +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + +// REQUIRES: asserts +// RUN: not %target-swift-frontend %s -emit-ir +protocol P{ +typealias e:RangeReplaceableCollection +}{}extension P{{}func e +typealias e:FlattenCollection diff --git a/validation-test/compiler_crashers_fixed/28793-nestedpabyname-didnt-find-the-associated-type-we-wanted.swift b/validation-test/compiler_crashers_fixed/28793-nestedpabyname-didnt-find-the-associated-type-we-wanted.swift new file mode 100644 index 00000000000..efc3af830ae --- /dev/null +++ b/validation-test/compiler_crashers_fixed/28793-nestedpabyname-didnt-find-the-associated-type-we-wanted.swift @@ -0,0 +1,13 @@ +// This source file is part of the Swift.org open source project +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + +// REQUIRES: asserts +// RUN: not %target-swift-frontend %s -emit-ir +protocol A:RangeReplaceableCollection +protocol P{ +protocol A +class a:A{}typealias a:A{}typealias a:RangeReplaceableCollection diff --git a/validation-test/compiler_crashers_fixed/28802-constrainttype-missing-constraint-type.swift b/validation-test/compiler_crashers_fixed/28802-constrainttype-missing-constraint-type.swift new file mode 100644 index 00000000000..df54499ba8b --- /dev/null +++ b/validation-test/compiler_crashers_fixed/28802-constrainttype-missing-constraint-type.swift @@ -0,0 +1,10 @@ +// This source file is part of the Swift.org open source project +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + +// REQUIRES: asserts +// RUN: not %target-swift-frontend %s -emit-ir +class a